{"_id":"@adib23704/queryguard","_rev":"4-2c90e9ea6337286baaf86cbdc5928c55","name":"@adib23704/queryguard","dist-tags":{"latest":"1.0.3"},"versions":{"1.0.0":{"name":"@adib23704/queryguard","version":"1.0.0","author":"Adib23704","license":"MIT","_id":"@adib23704/queryguard@1.0.0","maintainers":[{"name":"adib23704","email":"adib23704@gmail.com"}],"bin":{"queryguard":"./dist/bin/queryguard.js"},"dist":{"shasum":"350e0d3b04561d83c2b26562eaf0bc74d2377dce","tarball":"https://registry.npmjs.org/@adib23704/queryguard/-/queryguard-1.0.0.tgz","fileCount":52,"integrity":"sha512-I7h19D6h8Y65FUmgMSCjahydmyEcLYkno7W0c07RN46+ue1ecDo930P+GuFyC/DoS0eDV1yKevuM3nS5NTsINA==","signatures":[{"sig":"MEYCIQD5hUSTNcn0gMl7LVPGLWFmkVUFZyKrDoaHhtxqvVM46gIhAKgSVfgzLCTvCmvViS2UGyK8mQFHZSIdasIS9KAz6lmP","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":392756},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","scripts":{"lint":"biome check .","test":"vitest run","build":"tsup && tsc -p tsconfig.build.json","format":"biome format --write .","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"adib23704","email":"adib23704@gmail.com"},"description":"Zero-config PostgreSQL wire-protocol proxy, N+1 query cascade detector, and automated index advisor","directories":{},"_nodeVersion":"24.16.0","dependencies":{"pg":"^8.23.0","commander":"^15.0.0","cli-table3":"^0.6.5","picocolors":"^1.1.1","cross-spawn":"^7.0.6","pg-protocol":"^1.16.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","vitest":"^4.1.11","@types/pg":"^8.23.1","typescript":"^7.0.2","@types/node":"^26.4.0","@biomejs/biome":"^2.5.11","@types/cross-spawn":"^6.0.6"},"_npmOperationalInternal":{"tmp":"tmp/queryguard_1.0.0_1788159945857_0.9372634615471918","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@adib23704/queryguard","version":"1.0.1","author":"Adib23704","license":"MIT","_id":"@adib23704/queryguard@1.0.1","maintainers":[{"name":"adib23704","email":"adib23704@gmail.com"}],"homepage":"https://github.com/Adib23704/QueryGuard#readme","bugs":{"url":"https://github.com/Adib23704/QueryGuard/issues"},"bin":{"queryguard":"./dist/bin/queryguard.js"},"dist":{"shasum":"c95ded85bc201a867f2e45c5fa558ac5617d640b","tarball":"https://registry.npmjs.org/@adib23704/queryguard/-/queryguard-1.0.1.tgz","fileCount":51,"integrity":"sha512-yYm9kkfRkZRCUQVRKxwmcT+XP5ej0ThaqvLpuKbXG+anyZqLRELqUZzhVTuTW75csP/oMZHWPBCYkiN9VBFgIg==","signatures":[{"sig":"MEYCIQDg46RAeFZaRkrIaSWisBZ1HBx4lk/uQCg1XFhXwksCTgIhAKT42z+l+1dBjsss/9IhJfvUm0maZsZOMrWa6OxvT5sB","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":388840},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","scripts":{"lint":"biome check .","test":"vitest run","build":"tsup && tsc -p tsconfig.build.json","format":"biome format --write .","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"adib23704","email":"adib23704@gmail.com"},"repository":{"url":"git+https://github.com/Adib23704/QueryGuard.git","type":"git"},"description":"Zero-config PostgreSQL wire-protocol proxy, N+1 query cascade detector, and automated index advisor","directories":{},"_nodeVersion":"24.16.0","dependencies":{"pg":"^8.23.0","commander":"^15.0.0","cli-table3":"^0.6.5","picocolors":"^1.1.1","cross-spawn":"^7.0.6","pg-protocol":"^1.16.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","vitest":"^4.1.11","@types/pg":"^8.23.1","typescript":"^7.0.2","@types/node":"^26.4.0","@biomejs/biome":"^2.5.11","@types/cross-spawn":"^6.0.6"},"_npmOperationalInternal":{"tmp":"tmp/queryguard_1.0.1_1788160685334_0.9428930871664294","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@adib23704/queryguard","version":"1.0.2","keywords":["postgresql","postgres","database","performance","n-plus-one","n1","index-advisor","sql","proxy","wire-protocol","prisma","drizzle-orm","typeorm","kysely","explain","ci-cd","github-action"],"author":"Adib23704","license":"MIT","_id":"@adib23704/queryguard@1.0.2","maintainers":[{"name":"adib23704","email":"adib23704@gmail.com"}],"homepage":"https://github.com/Adib23704/QueryGuard#readme","bugs":{"url":"https://github.com/Adib23704/QueryGuard/issues"},"bin":{"queryguard":"./dist/bin/queryguard.js"},"dist":{"shasum":"ed4b3c577c2d580c501be3f1d938050de5329951","tarball":"https://registry.npmjs.org/@adib23704/queryguard/-/queryguard-1.0.2.tgz","fileCount":51,"integrity":"sha512-dHax5fq3zlUsyRoVbouQ5xQNA3z2y1KkD9sTSxEHJxG5KmC4JxndXF8Y/3GV6R25OLpf269YW8nN1fY4MxwOZg==","signatures":[{"sig":"MEYCIQCSFDZMOCxs1iDZ40SbODI4XpMGohznq0LAGoc57OQbjAIhAImacMuu/sKnga08x0cm+N3EykSzsODgRPEhHOT6DeXx","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":389130},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","scripts":{"lint":"biome check .","test":"vitest run","build":"tsup && tsc -p tsconfig.build.json","format":"biome format --write .","typecheck":"tsc --noEmit","test:watch":"vitest"},"_npmUser":{"name":"adib23704","email":"adib23704@gmail.com"},"repository":{"url":"https://github.com/Adib23704/QueryGuard.git","type":"git"},"description":"Zero-config PostgreSQL wire-protocol proxy, N+1 query cascade detector, and automated index advisor","directories":{},"_nodeVersion":"24.16.0","dependencies":{"pg":"^8.23.0","commander":"^15.0.0","cli-table3":"^0.6.5","picocolors":"^1.1.1","cross-spawn":"^7.0.6","pg-protocol":"^1.16.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","vitest":"^4.1.11","@types/pg":"^8.23.1","typescript":"^7.0.2","@types/node":"^26.4.0","@biomejs/biome":"^2.5.11","@types/cross-spawn":"^6.0.6"},"_npmOperationalInternal":{"tmp":"tmp/queryguard_1.0.2_1788161530938_0.30460065208603115","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@adib23704/queryguard","version":"1.0.3","description":"Zero-config PostgreSQL wire-protocol proxy, N+1 query cascade detector, and automated index advisor","type":"module","license":"MIT","publishConfig":{"access":"public"},"author":"Adib23704","keywords":["postgresql","postgres","database","performance","n-plus-one","n1","index-advisor","sql","proxy","wire-protocol","prisma","drizzle-orm","typeorm","kysely","explain","ci-cd","github-action"],"repository":{"type":"git","url":"https://github.com/Adib23704/QueryGuard.git"},"bugs":{"url":"https://github.com/Adib23704/QueryGuard/issues"},"homepage":"https://github.com/Adib23704/QueryGuard#readme","main":"./dist/index.js","types":"./dist/index.d.ts","bin":{"queryguard":"./dist/bin/queryguard.js"},"dependencies":{"cli-table3":"^0.6.5","commander":"^15.0.0","cross-spawn":"^7.0.6","pg":"^8.23.0","pg-protocol":"^1.16.0","picocolors":"^1.1.1"},"devDependencies":{"@biomejs/biome":"^2.5.11","@types/cross-spawn":"^6.0.6","@types/node":"^26.4.0","@types/pg":"^8.23.1","tsup":"^8.5.1","typescript":"^7.0.2","vitest":"^4.1.11"},"scripts":{"build":"tsup && tsc -p tsconfig.build.json","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest","lint":"biome check .","format":"biome format --write ."},"_nodeVersion":"24.16.0","_id":"@adib23704/queryguard@1.0.3","dist":{"integrity":"sha512-ikq6RZaCcH6RG56dcnlWWy5e2GkjgKLMySRPiDQQ5xdlZGGhB67QdfNI0hnJqsEE0Owgpnk7jTs4mdY43+xGSg==","shasum":"ca6aff3a2b21910448d0553bbcbd4e8039f5f5f8","tarball":"https://registry.npmjs.org/@adib23704/queryguard/-/queryguard-1.0.3.tgz","fileCount":51,"unpackedSize":389130,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIHtFB4vXieZ7ksmRxKteNk5WY06m/2NWHrzQ5PsEHi5XAiEAoyOQPeV7mKm4GU4Iyk2EOn8gQs1KiI5W5UTjy+mmP50="}]},"_npmUser":{"name":"adib23704","email":"adib23704@gmail.com"},"directories":{},"maintainers":[{"name":"adib23704","email":"adib23704@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/queryguard_1.0.3_1788161802590_0.7826910980198873"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-31T07:05:45.486Z","modified":"2026-08-31T07:36:42.956Z","1.0.0":"2026-08-31T07:05:46.017Z","1.0.1":"2026-08-31T07:18:05.531Z","1.0.2":"2026-08-31T07:32:11.098Z","1.0.3":"2026-08-31T07:36:42.738Z"},"bugs":{"url":"https://github.com/Adib23704/QueryGuard/issues"},"author":"Adib23704","license":"MIT","homepage":"https://github.com/Adib23704/QueryGuard#readme","keywords":["postgresql","postgres","database","performance","n-plus-one","n1","index-advisor","sql","proxy","wire-protocol","prisma","drizzle-orm","typeorm","kysely","explain","ci-cd","github-action"],"repository":{"type":"git","url":"https://github.com/Adib23704/QueryGuard.git"},"description":"Zero-config PostgreSQL wire-protocol proxy, N+1 query cascade detector, and automated index advisor","maintainers":[{"name":"adib23704","email":"adib23704@gmail.com"}],"readme":"# 🛡️ QueryGuard\n\n> **High-performance, zero-code-change PostgreSQL wire-protocol proxy, $N+1$ query cascade detector, sequential table scan analyzer, and automated index advisor for Node.js/TypeScript and CI/CD environments.**\n\n[![CI](https://github.com/Adib23704/QueryGuard/actions/workflows/ci.yml/badge.svg)](https://github.com/Adib23704/QueryGuard/actions/workflows/ci.yml)\n[![npm version](https://img.shields.io/npm/v/@adib23704/queryguard.svg)](https://www.npmjs.com/package/@adib23704/queryguard)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)\n\n---\n\n## Why QueryGuard?\n\nModern ORMs (Prisma, Drizzle, TypeORM, Sequelize) make data modeling effortless during development, but frequently introduce catastrophic performance anti-patterns into production:\n\n- **$N+1$ Query Cascades:** Running hundreds of repetitive queries inside loops instead of batched fetches (`WHERE id IN (...)`).\n- **Unindexed Sequential Scans:** Executing `SELECT` queries against tables with thousands of rows without matching indexes on filtered columns.\n- **Redundant Duplicate Queries:** Repeating identical queries with identical parameters multiple times within the same request lifecycle.\n\nExisting monitoring tools require invasive application wrappers or heavyweight APM agents. **QueryGuard operates at the PostgreSQL TCP wire-protocol layer (3.0)** during test runs or CI/CD pipelines with **zero application code changes**.\n\n---\n\n## Architecture & How It Works\n\n```\n                     +--------------------------------------------------------+\n                     |                 npx queryguard exec                    |\n                     |                                                        |\n                     |  1. Spawns QueryGuard TCP Proxy on localhost:5433       |\n                     |  2. Injects rewritten DATABASE_URL into child process  |\n                     |  3. Spawns test suite (e.g. `pnpm test`)               |\n                     +---------------------------+----------------------------+\n                                                 |\n                            [Client Connections] |\n                                                 v\n                     +--------------------------------------------------------+\n                     |                 QueryGuard Proxy Core                  |\n                     |  - TCP Wire-Level Stream Interceptor (Port 5433)       |\n                     |  - PostgreSQL 3.0 Frame Parser (Simple & Extended)     |\n                     |  - High-Throughput Bidirectional Socket Bridge         |\n                     +---------------------------+----------------------------+\n                                                 |\n                          +----------------------+----------------------+\n                          |                                             |\n                          v                                             v\n         +----------------------------------+          +----------------------------------+\n         |      Real PostgreSQL Server      |          |        Diagnostic Engine         |\n         |         (localhost:5432)         |          |  - Deterministic SHA-256 Hasher  |\n         +----------------------------------+          |  - Connection Session Grouping   |\n                                                       |  - N+1 Cascade Matcher           |\n                                                       |  - Active EXPLAIN Index Advisor  |\n                                                       +----------------+-----------------+\n                                                                        |\n                                                                        v\n                                                       +----------------------------------+\n                                                       |         Report Formats           |\n                                                       |  - Colorized Terminal Table      |\n                                                       |  - GitHub PR Comment Markdown    |\n                                                       |  - Standalone HTML Waterfall     |\n                                                       |  - Structured JSON Output        |\n                                                       +----------------------------------+\n```\n\n---\n\n## Quickstart\n\n### 1. Run with your test suite (Zero Code Changes)\n\nWrap your existing test command with `queryguard exec`:\n\n```bash\n# Using npx\nnpx queryguard exec -- pnpm test\n\n# Using npm / yarn / bun\nnpx queryguard exec -- npm test\nnpx queryguard exec -- yarn test\nnpx queryguard exec -- bun test\n```\n\nQueryGuard will:\n1. Bind a transparent TCP proxy to `localhost:5433`.\n2. Rewrite `DATABASE_URL` to point to the proxy.\n3. Forward all traffic to your target PostgreSQL server while recording millisecond-accurate query traces.\n4. Output a colorized performance summary table on test completion.\n\n### 2. Standalone Trace File Analysis\n\nAnalyze an exported query trace offline:\n\n```bash\nnpx queryguard analyze --file .queryguard/traces.json --db-url postgresql://postgres:password@localhost:5432/mydb\n```\n\n---\n\n## Report Formats\n\n### 1. Terminal Output\nInstant ANSI-colorized table displaying captured queries, latency waste, N+1 cascades, and index suggestions right in your terminal.\n\n### 2. GitHub Actions PR Comment (Markdown)\nAutomatically posts a formatted diagnostic comment on pull requests with collapsible `<details>` blocks for each query regression.\n\n### 3. Standalone Interactive HTML Waterfall\nZero-external-dependency, self-contained HTML dashboard featuring:\n- **KPI Grid:** Total queries, unique signatures, total query duration, and wasted latency.\n- **Execution Waterfall Timeline:** Color-coded execution bars (Cyan = normal, Yellow = duplicate, Red = N+1 cascade).\n- **Searchable Query Table:** Instant full-text filtering by SQL, table, or parameters.\n- **Index Advisor:** Copy-to-clipboard `CREATE INDEX CONCURRENTLY` DDL suggestions.\n\n---\n\n## GitHub Actions CI Integration\n\nAdd QueryGuard to your pull request workflow to block regressions before merging:\n\n```yaml\nname: Test Suite & Performance Gate\n\non:\n  pull_request:\n    branches: [main]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    services:\n      postgres:\n        image: postgres:16-alpine\n        env:\n          POSTGRES_USER: postgres\n          POSTGRES_PASSWORD: password\n          POSTGRES_DB: app_test\n        ports:\n          - 5432:5432\n        options: >-\n          --health-cmd pg_isready\n          --health-interval 10s\n          --health-timeout 5s\n          --health-retries 5\n\n    steps:\n      - uses: actions/checkout@v7\n      - uses: pnpm/setup@v1\n        with:\n          version: 11\n          runtime: node@24\n          cache: true\n\n      - run: pnpm install\n\n      - name: Run QueryGuard Performance Gate\n        uses: Adib23704/QueryGuard@v1\n        env:\n          DATABASE_URL: postgres://postgres:password@localhost:5432/app_test\n        with:\n          command: \"pnpm test\"\n          fail_on_n_plus_one: \"true\"\n          fail_on_seq_scan: \"false\"\n          markdown_report: \".queryguard/report.md\"\n          html_report: \".queryguard/report.html\"\n          github_token: ${{ secrets.GITHUB_TOKEN }}\n```\n\n---\n\n## CLI Reference\n\n### `queryguard exec [options] -- <command...>`\n\n| Flag | Description | Default |\n| :--- | :--- | :--- |\n| `-p, --port <number>` | Port for local TCP proxy to bind | `5433` |\n| `--db-url <url>` | Target PostgreSQL database connection string | `env.DATABASE_URL` |\n| `--fail-on-n-plus-one` | Exit with code 1 if N+1 query cascades are detected | `false` |\n| `--fail-on-seq-scan` | Exit with code 1 if sequential scans on large tables occur | `false` |\n| `--n-plus-one-threshold <number>` | Minimum repetitive queries to flag N+1 cascade | `5` |\n| `--seq-scan-threshold <number>` | Estimated row threshold to flag sequential scans | `100` |\n| `--html-report <path>` | File path to write standalone interactive HTML report | - |\n| `--markdown-report <path>` | File path to write GitHub PR comment markdown report | - |\n| `--json-report <path>` | File path to export structured JSON report | - |\n| `--silent` | Suppress terminal summary table output | `false` |\n| `--verbose` | Enable internal proxy diagnostic logging | `false` |\n\n---\n\n## Programmatic TypeScript Library API\n\nQueryGuard can also be used as a TypeScript library in custom test harnesses:\n\n```typescript\nimport { ProxyServer, analyzeTraces, renderTerminalReport, renderHtmlReport } from \"@adib23704/queryguard\";\n\n// 1. Start the proxy\nconst proxy = new ProxyServer({\n  targetHost: \"localhost\",\n  targetPort: 5432,\n  proxyPort: 5433,\n});\n\nawait proxy.start();\n\n// 2. Run your integration workload...\n\n// 3. Stop proxy and analyze captured traces\nawait proxy.stop();\n\nconst result = await analyzeTraces(proxy.getTraces(), proxy.getSessions(), {\n  nPlusOneThreshold: 5,\n  seqScanRowThreshold: 100,\n  dbUrl: \"postgresql://postgres:password@localhost:5432/mydb\",\n  enableExplain: true,\n});\n\n// 4. Output reports\nconsole.log(renderTerminalReport(result));\n```\n\n---\n\n## Supported Frameworks & ORMs\n\nQueryGuard intercepts traffic at the network socket layer, making it compatible with all PostgreSQL clients:\n\n- **Prisma**\n- **Drizzle ORM**\n- **TypeORM**\n- **Kysely**\n- **Knex.js**\n- **Sequelize**\n- **MikroORM**\n- **node-postgres (`pg`)**\n- **postgres.js (`postgres`)**\n\n---\n\n## License\n\nMIT © [Adib23704](https://github.com/Adib23704)\n","readmeFilename":""}