{"_id":"@allodium/db","_rev":"4-b829745e7a7289de613fe18e54ab181f","name":"@allodium/db","dist-tags":{"latest":"0.2.0"},"versions":{"0.0.1":{"name":"@allodium/db","version":"0.0.1","license":"MIT","_id":"@allodium/db@0.0.1","maintainers":[{"name":"glossydev","email":"adam@glossydev.com"}],"dist":{"shasum":"40bed1d56121d38a277c3220be096ad8ae5e14e3","tarball":"https://registry.npmjs.org/@allodium/db/-/db-0.0.1.tgz","fileCount":5,"integrity":"sha512-aqrb7tx9pJElDTOV/aMEw0rg05Uus4gzeN7aWnMlv22VmkWiWrRG8VhPXq+xeqP3Rr2UPChyRGYBhzXHPTZRuA==","signatures":[{"sig":"MEUCIQCP8zhxb12BPGvt07vL2yPqJeTxQZgWcQR6x4Z7dTnA5QIgTVX2efsFCohzHGICrpvzxSSwf+xgIPxDrzVbLbPdhag=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":6993},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"dcb271a2b5c97f5e238f9debb419b91837bd8763","scripts":{"build":"tsc -p tsconfig.json","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"glossydev","email":"adam@glossydev.com"},"_npmVersion":"11.5.2","description":"Postgres data-layer conventions for Allodium: pooling, transactions, typed query-module patterns on Drizzle + node-postgres.","directories":{},"_nodeVersion":"22.18.0","_hasShrinkwrap":false,"devDependencies":{"pg":"^8.13.0","@types/pg":"^8.11.0","drizzle-orm":"^0.45.0"},"peerDependencies":{"pg":">=8.11.0","drizzle-orm":">=0.38.0"},"_npmOperationalInternal":{"tmp":"tmp/db_0.0.1_1785044976636_0.6555638307065603","host":"s3://npm-registry-packages-npm-production"}},"0.1.0":{"name":"@allodium/db","version":"0.1.0","license":"MIT","_id":"@allodium/db@0.1.0","maintainers":[{"name":"glossydev","email":"adam@glossydev.com"}],"dist":{"shasum":"f35d18dc9eebfb97b785994eaa8bd8a0c9201c25","tarball":"https://registry.npmjs.org/@allodium/db/-/db-0.1.0.tgz","fileCount":13,"integrity":"sha512-wgcxEfXTqsbhlow9jvaRbrIfsVHjUB0TwjZ2mXzyTczk0j7E7rJUHaTqixLOOyCKa3qC2IhinivdS5sjwct0SA==","signatures":[{"sig":"MEUCIQDYAFhzLKJaLQKhn7lhE4ll4S/ZX0mFc8kzVY2v2k301QIgS+p+bwMVkLgngsqOleUakT627lyoO1QbvynFHyxcK/4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":18241},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"8ab1ee16a4894c1b4f928760bc317c63ffc9245d","scripts":{"build":"tsc -p tsconfig.json","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"glossydev","email":"adam@glossydev.com"},"_npmVersion":"11.5.2","description":"Postgres data-layer conventions for Allodium: pooling, transactions, typed query-module patterns on Drizzle + node-postgres.","directories":{},"_nodeVersion":"22.18.0","_hasShrinkwrap":false,"devDependencies":{"pg":"^8.13.0","@types/pg":"^8.11.0","drizzle-orm":"^0.45.0"},"peerDependencies":{"pg":">=8.11.0","drizzle-orm":">=0.38.0"},"_npmOperationalInternal":{"tmp":"tmp/db_0.1.0_1785202361022_0.4022201316257481","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@allodium/db","version":"0.1.1","license":"MIT","_id":"@allodium/db@0.1.1","maintainers":[{"name":"glossydev","email":"adam@glossydev.com"}],"dist":{"shasum":"131150ed89f128c13b405b8d32e75a6140528237","tarball":"https://registry.npmjs.org/@allodium/db/-/db-0.1.1.tgz","fileCount":13,"integrity":"sha512-5IOKe45d9hxSP9we05iBIuAI5olWNbSuUEu/wvSLXpi4yP8g6Hri62VqzgSd9wnfbgFj3hN1aJ7Uel6FQKaMlA==","signatures":[{"sig":"MEQCIGo7qlG8LpKwLsGGdURHkTDlLAxfQdlSOzRQz+UB8V1DAiADgezcc58ybCOHcZXiqmT0UNyWH8KZA4EfqQNqhnbZxQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":18814},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"8ab1ee16a4894c1b4f928760bc317c63ffc9245d","scripts":{"build":"tsc -p tsconfig.json","typecheck":"tsc -p tsconfig.json --noEmit"},"_npmUser":{"name":"glossydev","email":"adam@glossydev.com"},"_npmVersion":"11.5.2","description":"Postgres data-layer conventions for Allodium: pooling, transactions, typed query-module patterns on Drizzle + node-postgres.","directories":{},"_nodeVersion":"22.18.0","_hasShrinkwrap":false,"devDependencies":{"pg":"^8.13.0","@types/pg":"^8.11.0","drizzle-orm":"^0.45.0"},"peerDependencies":{"pg":">=8.11.0","drizzle-orm":">=0.38.0"},"_npmOperationalInternal":{"tmp":"tmp/db_0.1.1_1785202896686_0.0853678994745819","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@allodium/db","version":"0.2.0","description":"Postgres data-layer conventions for Allodium: pooling, transactions, typed query-module patterns on Drizzle + node-postgres.","license":"MIT","repository":{"type":"git","url":"git+https://github.com/glossydev/allodium.git","directory":"packages/db"},"type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./package.json":"./package.json"},"scripts":{"build":"tsc -p tsconfig.json","typecheck":"tsc -p tsconfig.json --noEmit"},"peerDependencies":{"drizzle-orm":">=0.38.0","pg":">=8.11.0"},"devDependencies":{"@types/pg":"^8.11.0","drizzle-orm":"^0.45.0","pg":"^8.13.0"},"engines":{"node":">=20"},"gitHead":"8374294b8cb9f031760ef63f6a0fb82123c0ee1f","_id":"@allodium/db@0.2.0","bugs":{"url":"https://github.com/glossydev/allodium/issues"},"homepage":"https://github.com/glossydev/allodium#readme","_nodeVersion":"22.23.2","_npmVersion":"12.0.2","dist":{"integrity":"sha512-aroB1W/aj45rVS7ZNbul/KsiSQrczsjG5/Rk+/JFntd/E9Ntq5fLKgXqVsHtukcfDk8zphYungPJpjaK84pTfA==","shasum":"bc977f04e4091651c5095766935ba6d83ac30f35","tarball":"https://registry.npmjs.org/@allodium/db/-/db-0.2.0.tgz","fileCount":15,"unpackedSize":23194,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@allodium%2fdb@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIEDEzeBJSlAhYpdB0Z5xHQOMcVE9lV9p6QLiFPml2WyWAiEAoJJAB8nBZg5aTnYgibwm+TbNiS4Q0kKGEUOk/0sB99c="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:f8174b0b-6f00-4838-a186-cf85e7443c0b"}},"directories":{},"maintainers":[{"name":"glossydev","email":"adam@glossydev.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/db_0.2.0_1789062298363_0.22986856897170438"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-26T05:49:36.452Z","modified":"2026-09-10T17:44:58.817Z","0.0.1":"2026-07-26T05:49:36.782Z","0.1.0":"2026-07-28T01:32:41.148Z","0.1.1":"2026-07-28T01:41:36.829Z","0.2.0":"2026-09-10T17:44:58.501Z"},"license":"MIT","description":"Postgres data-layer conventions for Allodium: pooling, transactions, typed query-module patterns on Drizzle + node-postgres.","maintainers":[{"name":"glossydev","email":"adam@glossydev.com"}],"readme":"# @allodium/db\n\nThe data-layer seam: one pool, honest money, and a wire boundary that doesn't corrupt\nyour timestamps.\n\nSmall on purpose. Every function here exists because its absence caused a bug in\nproduction — most of them twice.\n\n```bash\nnpm install @allodium/db\nnpm install pg drizzle-orm     # peers\n```\n\nRequires Node 20+ and PostgreSQL.\n\n## The pool\n\n```ts\nimport { createDb, singleton } from '@allodium/db';\nimport * as schema from './schema';\n\nexport const { db, pool, close } = singleton('db', () => createDb(schema, { max: 10 }));\n```\n\n`singleton` exists for Next.js dev, where hot reload re-evaluates modules and a plain\n`createDb` leaks a new pool on every save until Postgres refuses connections. In\nproduction it is a plain call.\n\n`close()` belongs in your process signal handlers.\n\n## Money\n\n```ts\nimport { money, numeric } from '@allodium/db';\n\nmoney(19.999)            // 20    — 2dp, rounded at the boundary\nnumeric('45.00')         // 45    — Postgres NUMERIC arrives as a string\n```\n\nPostgres `NUMERIC` comes back from the driver as a **string**, because it cannot fit in\na JS float without losing precision. Use `numeric()` in your query mappers so route code\nnever sees `\"45.00\"` and never accidentally does `\"45.00\" + 5`.\n\n## The wire boundary\n\n```ts\nimport { toWireRow, toWireRows } from '@allodium/db';\n\nreturn Response.json({ order: toWireRow(orders, row) });\n```\n\n`toWireRow` maps a Drizzle row to its SQL column names and normalizes timestamps to ISO\nstrings. The normalizers are also exported directly:\n\n| | |\n|---|---|\n| `pgTimestamptzToIso` | `timestamptz` text → ISO. Pads bare-hour offsets (`+00` → `+00:00`), which `new Date()` parses inconsistently across runtimes, and guards `isNaN` rather than emitting `\"Invalid Date\"`. |\n| `pgNaiveToIso` | `timestamp` (no zone) → ISO, fraction stripped. |\n| `normalizePgTimestamp` | Picks the right one. |\n\n**This is the bug-class the package exists for.** Hand-rolled timestamp handling shipped\nbroken twice in the reference deployment — once producing `Invalid Date` in an API\nresponse, once shifting every timestamp by the server's offset. The fix is three lines\nand belongs in one place.\n\n## Unique-violation detection\n\n```ts\nimport { isUniqueViolation } from '@allodium/db';\n\ntry {\n  await db.insert(users).values({ email });\n} catch (e) {\n  if (isUniqueViolation(e, 'users_email_key')) return { error: 'That email is taken' };\n  throw e;\n}\n```\n\n**Walks the cause chain.** Drizzle wraps the `pg` `DatabaseError`, so the naive\n`e.code === '23505'` check silently never fires and you return a 500 for what should be\na friendly message. Optionally match a constraint name so \"email taken\" and \"username\ntaken\" stay distinguishable.\n\n## Design notes\n\n**Peer dependencies.** `pg` and `drizzle-orm` are peers, never bundled — you control the\nversions, and there is no chance of two copies of the driver disagreeing about pool\nstate.\n\n**No environment reads.** `createDb` takes `connectionString` explicitly (falling back to\n`DATABASE_URL` only if you omit it). The rest of the toolkit follows the same rule.\n\n## License\n\nMIT. No CLA.\n","readmeFilename":"README.md","homepage":"https://github.com/glossydev/allodium#readme","repository":{"type":"git","url":"git+https://github.com/glossydev/allodium.git","directory":"packages/db"},"bugs":{"url":"https://github.com/glossydev/allodium/issues"}}