{"_id":"@airdraft/db-adapter-postgres","_rev":"3-27c8420eac357d6cb60aac6e95d174cf","name":"@airdraft/db-adapter-postgres","dist-tags":{"latest":"0.1.2"},"versions":{"0.1.0":{"name":"@airdraft/db-adapter-postgres","version":"0.1.0","license":"MIT","_id":"@airdraft/db-adapter-postgres@0.1.0","maintainers":[{"name":"miracleio","email":"miracleficient@gmail.com"}],"dist":{"shasum":"9bccf1057901d28d61668a42099800ae6a1d8d6c","tarball":"https://registry.npmjs.org/@airdraft/db-adapter-postgres/-/db-adapter-postgres-0.1.0.tgz","fileCount":10,"integrity":"sha512-mMz7CP71YLSklZzZswTRaePz65YY8fjD1HAwWGyYByX9QTj/eP1idSRxW13O5JwXswd9cydfHk2FLrG3EwmFlg==","signatures":[{"sig":"MEUCIAsFRn5iVxZS0Iz2KdcW+fSCUCb+NIYAfsPbGMIHvHARAiEAks5TgYyxyFucInaQPn6U54W8HtGYWRtHMlZnocTZioI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":43170},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"487fa21cb4354fe9f328783fc337269784e1262c","scripts":{"dev":"tsc --watch","test":"vitest run","build":"tsc","clean":"rm -rf dist","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"miracleio","email":"miracleficient@gmail.com"},"_npmVersion":"11.9.0","description":"Airdraft PostgreSQL database adapter via pg","directories":{},"_nodeVersion":"24.14.0","dependencies":{"@airdraft/core":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"pg":">=8.0.0","vitest":"^2.0.0","@types/pg":"^8.0.0","typescript":"^5.4.0","@types/node":"^20.0.0","@airdraft/db-adapter":"*","@electric-sql/pglite":"^0.2.0"},"peerDependencies":{"pg":">=8.0.0","@airdraft/db-adapter":">=0.1.0"},"_npmOperationalInternal":{"tmp":"tmp/db-adapter-postgres_0.1.0_1780295190406_0.6040170408254517","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@airdraft/db-adapter-postgres","version":"0.1.1","license":"MIT","_id":"@airdraft/db-adapter-postgres@0.1.1","maintainers":[{"name":"miracleio","email":"miracleficient@gmail.com"}],"dist":{"shasum":"a7e0ddd2a6384f4b3992ab6a770f63a238b4034b","tarball":"https://registry.npmjs.org/@airdraft/db-adapter-postgres/-/db-adapter-postgres-0.1.1.tgz","fileCount":10,"integrity":"sha512-SpY0gVkU24Ic7AxvmO8PPYYmapjmr6/vzHwSm5CHZBR6LfNfYsPYcgti9wa3JXE7NfyfCsVPGxBeuw7DxyaUzA==","signatures":[{"sig":"MEYCIQDBHTqwfHaboxbBIX7GX5PkF2drNa4Y7Z0VDQaZNi4jDAIhANmYdSFNwbSzuFTcwvYGryP6+/ZS/p+ijt2+Cs96pxoO","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":43277},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"9fdb3e0fbca1e58bb84aca8dd92155d0057ca4b1","scripts":{"dev":"tsc --watch","test":"vitest run","build":"tsc","clean":"rm -rf dist","typecheck":"tsc --noEmit","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"miracleio","email":"miracleficient@gmail.com"},"_npmVersion":"11.9.0","description":"Airdraft PostgreSQL database adapter via pg","directories":{},"_nodeVersion":"24.14.0","dependencies":{"@airdraft/core":"*"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"pg":">=8.0.0","vitest":"^2.0.0","@types/pg":"^8.0.0","typescript":"^5.4.0","@types/node":"^20.0.0","@airdraft/db-adapter":"*","@electric-sql/pglite":"^0.2.0"},"peerDependencies":{"pg":">=8.0.0","@airdraft/db-adapter":">=0.1.0"},"_npmOperationalInternal":{"tmp":"tmp/db-adapter-postgres_0.1.1_1782411667760_0.6814978366783919","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@airdraft/db-adapter-postgres","version":"0.1.2","description":"Airdraft PostgreSQL database adapter via pg","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"import":"./dist/index.js","types":"./dist/index.d.ts"}},"scripts":{"build":"tsc","dev":"tsc --watch","clean":"rm -rf dist","test":"vitest run","test:watch":"vitest","typecheck":"tsc --noEmit","prepublishOnly":"npm run build","release":"standard-version","release:patch":"standard-version --release-as patch","release:minor":"standard-version --release-as minor","release:major":"standard-version --release-as major"},"publishConfig":{"access":"public"},"license":"MIT","dependencies":{"@airdraft/core":"*"},"peerDependencies":{"@airdraft/db-adapter":">=0.1.0","pg":">=8.0.0"},"devDependencies":{"@airdraft/db-adapter":"*","@electric-sql/pglite":"^0.2.0","@types/node":"^20.0.0","@types/pg":"^8.0.0","pg":">=8.0.0","standard-version":"^9.5.0","typescript":"^5.4.0","vitest":"^2.0.0"},"gitHead":"d20236a8fba8458f9c30696a36380aded5d352db","_id":"@airdraft/db-adapter-postgres@0.1.2","_nodeVersion":"24.14.0","_npmVersion":"11.9.0","dist":{"integrity":"sha512-+5g8tTnli4eU75dZndFI9rrCM7GcvdihheHvq+fOLPqUA1WVhv+the/zsQ66gOlfNN/EljeNuHTuGhZhltp4Hg==","shasum":"acdbf31b8b0862dcefa1f096bca4e0c54ca24e3e","tarball":"https://registry.npmjs.org/@airdraft/db-adapter-postgres/-/db-adapter-postgres-0.1.2.tgz","fileCount":15,"unpackedSize":70503,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIHQtPa3zx/ReRranQyRLxbKs75u2O2j5KHPK66KuEhMjAiEAxtCZH858bIZTvGnzkKi3hqGSYHttEcuwhPIWnBAdXOQ="}]},"_npmUser":{"name":"miracleio","email":"miracleficient@gmail.com"},"directories":{},"maintainers":[{"name":"miracleio","email":"miracleficient@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/db-adapter-postgres_0.1.2_1782562668527_0.905474424375408"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-01T06:26:30.194Z","modified":"2026-06-27T12:17:48.826Z","0.1.0":"2026-06-01T06:26:30.547Z","0.1.1":"2026-06-25T18:21:07.914Z","0.1.2":"2026-06-27T12:17:48.677Z"},"license":"MIT","description":"Airdraft PostgreSQL database adapter via pg","maintainers":[{"name":"miracleio","email":"miracleficient@gmail.com"}],"readme":"# @airdraft/db-adapter-postgres\n\nPostgreSQL storage adapter for [Airdraft](https://airdraft.io) via [`pg`](https://node-postgres.com).\n\nUse this adapter to store Airdraft content in a PostgreSQL database — suitable for self-hosted deployments, managed cloud databases (Neon, Supabase, RDS, PlanetScale Postgres, etc.), and multi-tenant setups where multiple Airdraft projects share a single connection pool.\n\n---\n\n## Installation\n\n```bash\nnpm install @airdraft/db-adapter @airdraft/db-adapter-postgres pg\nnpm install -D @types/pg\n```\n\n---\n\n## Quick start\n\n```ts\n// airdraft.config.ts\nimport { defineConfig } from '@airdraft/core'\nimport { PostgresAdapter } from '@airdraft/db-adapter-postgres'\n\nexport default defineConfig({\n  adapter: new PostgresAdapter({\n    connectionString: process.env.DATABASE_URL!,\n  }),\n  // … collections, plugins\n})\n```\n\nAdd to `.env.local`:\n\n```\nDATABASE_URL=postgresql://user:pass@localhost:5432/mydb\n```\n\nRun the migration on first deploy (idempotent — safe to run on every deploy):\n\n```ts\n// instrumentation.ts  (Next.js server-start hook)\nimport airdraft from '@/airdraft.config'\nimport { BaseDatabaseAdapter } from '@airdraft/db-adapter'\n\nexport async function register() {\n  if (airdraft.adapter instanceof BaseDatabaseAdapter) {\n    await airdraft.adapter.migrate()\n  }\n}\n```\n\n---\n\n## Options\n\n```ts\nnew PostgresAdapter(options)\n```\n\n| Option | Type | Default | Description |\n|---|---|---|---|\n| `connectionString` | `string` | — | PostgreSQL connection string (`postgresql://…`). |\n| `pool` | `Pool` | — | Provide an existing `pg.Pool` to share across adapters (e.g. in multi-tenant cloud). Mutually exclusive with `connectionString`. |\n| `projectId` | `string` | `'default'` | Namespace for multi-tenant deployments. |\n| `history` | `boolean` | `false` | Mirror every write to `airdraft_entry_history`. |\n| `cacheTtlMs` | `number` | `0` | Per-entry read cache TTL. `0` disables caching. |\n| `cacheMaxSize` | `number` | `500` | Maximum entries in the LRU cache. |\n\n---\n\n## Schema\n\n### `airdraft_entries`\n\n| Column | Type | Notes |\n|---|---|---|\n| `id` | `SERIAL PRIMARY KEY` | |\n| `project_id` | `TEXT NOT NULL` | Multi-tenancy namespace |\n| `collection` | `TEXT NOT NULL` | |\n| `slug` | `TEXT NOT NULL` | |\n| `sha` | `TEXT NOT NULL` | SHA-256 of the serialized content |\n| `data` | `JSONB NOT NULL` | Entry data |\n| `published` | `BOOLEAN` | `NULL` = published (default), `FALSE` = draft |\n| `created_at` | `TIMESTAMPTZ` | |\n| `updated_at` | `TIMESTAMPTZ` | |\n\nUnique constraint on `(project_id, collection, slug)`. `pg` error code `23505` → `ConflictError`.\n\n### `airdraft_entry_history` *(when `history: true`)*\n\nSame columns as `airdraft_entries` minus `id`/`published`, plus a `SERIAL` history `id`.\n\n---\n\n## Features\n\n- **JSONB storage** — `data` is stored as native JSONB. Use `(data->>'field')::numeric` for numeric comparisons.\n- **Optimistic concurrency** — SHA checked on every write; `ConflictError` thrown on mismatch.\n- **Efficient pagination** — `COUNT(*) OVER()` window function returns total rows in a single query.\n- **Field filters** — `queryEntries()` maps `filter` entries to `data->>'field' = $n` predicates. `$contains` maps to `ILIKE`.\n- **Transactions** — history snapshots written inside a `BEGIN`/`COMMIT` block.\n- **Connection pooling** — Uses a `pg.Pool`; pass `pool` to share across multiple adapter instances.\n- **Atomic field ops** — `increment`, `set`, `push`, `pull` with SHA re-computation. `pull` correctly returns `[]` (not `NULL`) when the last element is removed.\n\n---\n\n## Multi-tenant cloud setup\n\nWhen many projects share one Postgres cluster, pass a shared pool and set `projectId` per project:\n\n```ts\nimport { Pool } from 'pg'\nimport { PostgresAdapter } from '@airdraft/db-adapter-postgres'\n\nconst pool = new Pool({ connectionString: process.env.DATABASE_URL })\n\n// per-project adapter, e.g. in a Next.js route handler\nconst adapter = new PostgresAdapter({ pool, projectId: project.slug })\n```\n\n---\n\n## Testing\n\nRuns the shared contract suite using [`@electric-sql/pglite`](https://pglite.dev) — a WASM Postgres that needs no Docker or external service:\n\n```bash\nnpm test\n```\n\nThe test file (`src/__tests__/contract.test.ts`) creates an in-memory PGlite instance, wraps it in a `pg.Pool`-compatible shim, and runs two suites: one without history and one with history enabled.\n\n---\n\n## License\n\nMIT\n","readmeFilename":"README.md"}