npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

pg-user-and-database-cdk

v1.3.0

Published

[![docs](https://img.shields.io/badge/docs-!-brightgreen)](https://isotoma.github.io/pg-user-and-database-cdk/) [![npm](https://img.shields.io/npm/v/pg-user-and-database-cdk)](https://www.npmjs.com/package/pg-user-and-database-cdk) [![NPM](https://img.shi

Readme

pg-user-and-database-cdk

docs npm NPM

Getting started

TODO

PostgresReadOnlyRole

A login role with SELECT on named tables and nothing else. Use it where something needs to read a few of an application's tables without holding the application's own credentials, such as a metrics job.

const app = new PostgresUserAndDatabase(this, 'UserAndDatabase', {
    dbCluster,
    dbSecret: dbClusterSecret,
    username: 'myapp',
    databaseName: 'myapp',
    vpc,
});

const reader = new PostgresReadOnlyRole(this, 'ReaderRole', {
    dbCluster,
    adminSecret: dbClusterSecret,
    ownerSecret: app.userSecret,
    roleName: 'myapp_reader',
    databaseName: 'myapp',
    tableNames: ['interesting_table'],
    vpc,
});

// reader.roleSecret holds host, port, dbname, username and password

That secret shape applies when the construct generates the secret, as above. Pass your own roleSecret instead and reader.roleSecret is exactly that secret, which only has to carry username and password — the connection details are yours to supply.

adminSecret and ownerSecret are both required, and the split between them is not the obvious one. Creating the role needs CREATEROLE, which the cluster admin has and the application user does not. Every GRANT has to come from the owner: on Aurora the master user is not a true superuser, and PostgresUserAndDatabase transfers database ownership to the application user, so the admin can grant neither CONNECT on the database nor SELECT on its tables. The CONNECT grant is the trap, since attempting it as the admin fails with nothing worse than WARNING: no privileges were granted.

One limitation on "nothing else": the role still inherits whatever PUBLIC holds. On a stock Postgres 16 database that is CONNECT and TEMPORARY, so the role can open temporary tables even though it was never granted anything beyond SELECT. That cannot be fixed per-role, because there is no way to revoke a PUBLIC grant from one role: it needs REVOKE TEMPORARY ON DATABASE <db> FROM PUBLIC, which changes the database for every role and so is left to the caller rather than done here. PUBLIC no longer has CREATE on the public schema, which changed in Postgres 15.

onCreateIfExists defaults to Fail. Adopting an existing role means resetting its password and granting it SELECT on the tables, so if the name turned out to belong to something else you would have quietly taken it over. Note the interaction with onDelete, which defaults to Retain: recreating a role that a previous stack left behind needs onCreateIfExists: 'Adopt'. Updates always adopt, since the resource already owns the role by then.

onDelete defaults to Retain, unlike PostgresUserAndDatabase. Removing the construct leaves the role in place rather than breaking whatever is still connecting with it; pass Drop to revoke the grants and drop the role.

With onDelete: 'Drop', avoid removing the owning PostgresUserAndDatabase in the same operation. The construct only takes ownerSecret, so CloudFormation has no dependency on the owner user itself, and every REVOKE has to run as that owner. If the owner is dropped first the revokes cannot authenticate and the stack deletion stalls. Remove the reader role in one deployment and the owner in the next, or drop the role by hand.

Adding a table to tableNames grants it on the next deploy. Removing one does not revoke it: that would mean tracking the previous property values, and a stale SELECT is the less surprising of the two failure modes. Use Drop and recreate if a grant genuinely needs removing.

Releasing

From an up-to-date main:

npm version minor    # or patch / major
git push && git push --tags

npm version bumps package.json, regenerates CHANGELOG.md, commits, and tags. .npmrc sets tag-version-prefix="", so the tag is 1.3.0 rather than v1.3.0, which is the form .github/workflows/publish.yaml triggers on. Pushing the tag builds and publishes to npm and deploys the typedoc output to gh-pages.

Do the bump and the tag together, which is what npm version is for. The publish job builds into build/, copies package.json in, and publishes from there, so npm publishes whatever the version field says and not what the tag says. Tagging 1.3.0 while package.json still reads 1.2.0 fails at npm publish, because that version already exists.

Approving the release

Pushing the tag does not put anything in front of consumers. The workflow uses staged publishing: the version lands in the registry but is not installable until a maintainer approves it with 2FA. So a compromised workflow cannot publish on its own.

After the tag job goes green, approve it in the Staged Packages tab on npmjs.com, or from the CLI:

npm stage list
npm stage approve <stage-id>

Either route prompts for 2FA, which is the point of the step. npm stage reject discards it instead. Note a staged version occupies its version number, so a rejected 1.3.0 has to be rejected before 1.3.0 can be staged again.

Authentication

Publishing uses npm trusted publishing over OIDC, so there is no NPM_TOKEN secret. The job requests id-token: write and the npm CLI exchanges that for a short-lived token by itself, which also means provenance attestations are generated automatically.

The trust relationship is configured on npmjs.com under the package's settings, naming the organisation, the repository, and the workflow filename (publish.yaml). It is configured to allow npm stage publish and not direct npm publish. Existing configurations cannot be edited, only deleted and recreated.

Staged publishing needs npm 11.15.0 or later, above the 11.5.1 that trusted publishing alone needs and above the 11.13.0 that Node 24 currently bundles, which is why the workflow installs npm explicitly. Below either floor the CLI quietly falls back to token authentication and fails with a misleading E404 on the PUT, so the workflow asserts the version rather than letting that happen.

OIDC covers npm publish and npm stage publish only. The approve, reject, list and view subcommands need interactive authentication and cannot use it.