Skip to content

feat(pg-node): add Node.js example using @e4a/pg-js#46

Merged
rubenhensen merged 2 commits into
mainfrom
feat/pg-node-example
May 24, 2026
Merged

feat(pg-node): add Node.js example using @e4a/pg-js#46
rubenhensen merged 2 commits into
mainfrom
feat/pg-node-example

Conversation

@rubenhensen
Copy link
Copy Markdown
Contributor

Summary

Adds a new sub-project pg-node/ — a plain Node.js CLI example showing how to use @e4a/pg-js from a server runtime. Mirrors the pg-sveltekit "Informatierijk notificeren" flow (citizen exact-email recipient + organisation email-domain recipient).

Two modes:

  • npm run send — encrypt + upload + ask Cryptify to mail recipients
  • npm run upload — encrypt + upload silently, return only the UUID

Configuration via .env (Node's built-in --env-file-if-exists), defaulting to staging. No bundler, no TypeScript build step — plain ESM (.mjs), runnable as soon as npm install finishes.

Why now

A partner integration (Bereken je Recht) is wiring @e4a/pg-js into a Node backend and hit several non-browser-runtime issues — see encryption4all/postguard-js#76 for the SDK-side fixes. This example serves as the known-good baseline for those use cases.

SDK dependency

package.json pins "@e4a/pg-js": "file:../../postguard-js" so local SDK changes are picked up immediately. Once encryption4all/postguard-js#76 merges and a release ships to npm, I'll swap this to "^X.Y.Z" in a follow-up commit. The README already explains the temporary file: link.

Verification

Ran end-to-end against pkg.staging.postguard.eu + storage.staging.postguard.eu in both modes, three real Cryptify UUIDs returned (last: babbfce1-2642-42c7-bccf-a10a92f8881a). Verified .env loading and explicit env-var loading both work.

Test plan

Mirrors the pg-sveltekit "Informatierijk notificeren" flow (citizen
exact-email recipient + organisation email-domain recipient) but as a
plain Node CLI script — drop-in starting point for backend integrations
that need to encrypt and upload from a server runtime.

Two modes:
  npm run send     # encrypt + upload + ask Cryptify to mail recipients
  npm run upload   # encrypt + upload silently, return only the UUID

Configuration via .env (loaded with Node's --env-file-if-exists). Defaults
to staging; flip PG_CRYPTIFY_URL to production for real mail delivery.

The package depends on @e4a/pg-js via "file:../../postguard-js" so local
SDK changes are picked up immediately after a rebuild — useful while the
non-browser-runtime support work is unreleased. Swap to a "^X.Y.Z"
version once the SDK ships to npm.
Copy link
Copy Markdown
Contributor

@dobby-coder dobby-coder Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code review

Stage 1 code-review findings were not available to this reviewer, so this review is rule-compliance focused. Spot-check of the diff itself: clean small change. New pg-node/ sub-project, ~380 lines, mirrors the pg-sveltekit "Informatierijk notificeren" flow as a CLI. Code is straightforward: env-driven config, two modes (send / upload-only), in-memory demo files fallback, abort handling on SIGINT, identical staging-detection heuristic to pg-sveltekit. PR body documents real end-to-end verification (3 staging UUIDs). Conventional-commit title, repo-root README updated to list the new sub-project plus a Development section pointing at the example.

Rule compliance

Checked the diff against the dobby-memory rule set and the postguard-examples repo notes. No blocking violations. A few small stylistic notes from writing-rules flagged in inline comments below — none are merge-blockers, and one is arguably load-bearing (the staging-doesn't-send-email callout has to read as a warning).

  • standardized-readmes: not applicable — sub-project READMEs aren't held to the repo-README template (matches pg-sveltekit / pg-dotnet / pg-manual conventions).
  • staging-cryptify-detection: matches the documented pattern (new URL(url).hostname.toLowerCase().includes('staging') inside try/catch). The download-URL branching (staging.postguard.eu vs postguard.eu) is the "if a separate staging download viewer is ever stood up" follow-up the memory note anticipated — good.
  • conventional-commit-pr-titles: feat(pg-node): ...
  • cross-repo-link-format: encryption4all/postguard-js#76 auto-links via the org-prefixed form ✓
  • pr-close-issue-keywords: no issue to close (this is a new feature referencing an upstream SDK PR, not resolving a tracker issue).
  • tests-required-on-fixes: not applicable — new example, not a fix; repo has no test suite by design (example/reference code only).
  • typo-sweep-template: no hits.
  • check-dep-is-used-before-bumping: not a bump; the one new dep (@e4a/pg-js) is used in src/encryption.mjs.
  • never-self-merge-prs: respected (this review does not merge).
  • Memory note refresh: repos/postguard-examples/notes.md says "No .github/workflows/" but pr-title.yml is now present in the repo. That memory note is stale; will update separately, not a PR concern.

Approving.

Comment thread pg-node/README.md

1. **Send** (`npm run send`) — encrypts the input files for a citizen (exact email) and an organisation (email domain), uploads to Cryptify, and asks Cryptify to email each recipient a download link.
2. **Upload-only** (`npm run upload`) — same encryption + upload, but silent. Cryptify returns a UUID you can distribute through some other channel.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Rule: writing-rules] Minor: the **Send** (...) — encrypts ... / **Upload-only** (...) — same encryption ... pattern is the "Inline header + colon/dash + sentence" list (writing-rules #48) plus the em-dash-overuse tell (#40). Same idea would read cleaner as plain sentences or a small table. Not a blocker — calling it out so it doesn't get copy-pasted into future example READMEs.

Comment thread pg-node/README.md
The `package.json` depends on the SDK via `file:../../postguard-js`, so any local changes you make to the SDK take effect after `cd ../../postguard-js && npm run build` followed by `cd ../postguard-examples/pg-node && npm install`. Swap that to `"^X.Y.Z"` once a real release is published.

## Run

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Rule: writing-rules] Em-dash count is on the high side for a short README (~10 across 75 lines). A few replace cleanly with a period or parentheses (e.g. Mirrors the pg-sveltekit example's flow — drop-in starting point... → just two sentences). Stylistic only.

import { PostGuard } from '@e4a/pg-js';
import { PKG_URL, CRYPTIFY_URL } from './config.mjs';

const pg = new PostGuard({ pkgUrl: PKG_URL, cryptifyUrl: CRYPTIFY_URL });
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Observation, not a rule violation: new PostGuard({ pkgUrl, cryptifyUrl }) runs at module import time, which means import from this file in a context where PKG_URL/CRYPTIFY_URL aren't yet set would silently bind to defaults. Fine for the CLI-only usage here; worth keeping in mind if this ever gets refactored into a library.

Comment thread pg-node/src/config.mjs
try {
return new URL(url).hostname.toLowerCase().includes('staging');
} catch {
return false;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Matches the documented staging-cryptify-detection pattern from the pg-sveltekit example — same new URL(url).hostname.toLowerCase().includes('staging') inside try/catch with false fallback. Good consistency.

Swaps the temporary file:../../postguard-js link for the published
^1.9.0 release on npm. Bumps the example's engines.node to >=22 to
match the SDK. README updated accordingly.

Verified end-to-end against staging.postguard.eu — real UUID returned
(bb90cb02-b27c-4b0d-a245-4acdb16056e1).
@rubenhensen
Copy link
Copy Markdown
Contributor Author

/dobby review this pr

@dobby-coder
Copy link
Copy Markdown
Contributor

dobby-coder Bot commented May 24, 2026

On it, @rubenhensen! This agent is most eager to review the new pg-node example PR — checking it over now.

@dobby-coder
Copy link
Copy Markdown
Contributor

dobby-coder Bot commented May 24, 2026

Plan

Re-reviewing on top of the new chore commit (2bf7463) — swaps file:../../postguard-js for the published @e4a/pg-js ^1.9.0 and bumps engines.node to >=22.

Checks done so far on Node v22.22.2:

  • @e4a/pg-js@1.9.0 published on npm with matching engines.node: ">=22"
  • npm install resolves clean; live import returns expected SDK surface (PostGuard, recipient.email/emailDomain, sign.apiKey, encrypt)
  • node --check passes on all .mjs files; missing PG_API_KEY boundary still handled
  • CI green, conventional PR title

Two stale references the bump missed (non-blocking, doc-only):

  • Root README.md:30 still says "Requires Node.js 20.6+"
  • pg-node/src/config.mjs:2 still says "(Node 20.6+)" and references --env-file= while scripts actually use --env-file-if-exists (Node 21.7+)

Will flag both as inline review comments and approve (the prior bot review already approved the feat commit; the chore commit is mechanically sound, the two refs are nits, not blockers).

Copy link
Copy Markdown
Contributor

@dobby-coder dobby-coder Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed after the chore commit that swapped the file:link for @e4a/pg-js ^1.9.0 and bumped engines.node to >=22.

Verification on Node v22.22.2:

  • @e4a/pg-js@1.9.0 published with matching engines.node: ">=22"
  • npm install resolves clean; live import returns the expected SDK surface (PostGuard, recipient.email/emailDomain, sign.apiKey, encrypt)
  • node --check passes on all .mjs files
  • Missing PG_API_KEY boundary still exits with code 2 and a clear message
  • CI green, conventional title (prior workflow run passed)

Two stale 20.6+ references the bump missed — flagged inline. Not blockers; both are doc-only and the example still runs correctly without fixing them. If you'd prefer to fold them into a tiny follow-up commit before merging, the two lines are noted.

Prior inline threads (em-dash/inline-header style, module-level singleton observation, staging-detection consistency) are unchanged by this commit. None are blockers either; the style nits stand for future copy-paste hygiene but are not worth blocking a working example.

Approving.

Comment thread README.md

### Node.js example

Requires Node.js 20.6+ and a PostGuard API key.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale after the engines bump. pg-node/package.json now requires node >= 22, but the root README still advertises 20.6+. Two consistent options: bump this to Node.js 22+ to match the sub-project's engines, or leave it at 20.6 with a sentence clarifying that pg-node specifically needs 22+. Recommend the former — simpler and matches pg-node/README.md:16.

Comment thread pg-node/src/config.mjs
@@ -0,0 +1,35 @@
// Env-driven config. Run with `node --env-file=.env index.mjs` to load
// from .env (Node 20.6+). Mirrors pg-sveltekit's config.ts.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also stale: the comment still says (Node 20.6+) and references --env-file=, but package.json scripts actually use --env-file-if-exists (added in Node 21.7) and engines.node is now >=22. Suggest: // from .env (Node 22+). Mirrors pg-sveltekit's config.ts. and drop the node --env-file=... snippet (scripts already wire this up).

@rubenhensen rubenhensen merged commit 0fb7789 into main May 24, 2026
1 check passed
@rubenhensen rubenhensen deleted the feat/pg-node-example branch May 24, 2026 13:42
rubenhensen added a commit that referenced this pull request May 24, 2026
Follow-up to dobby's review on the (already-merged) #46:

- Root README and pg-node/src/config.mjs still referenced "Node 20.6+"
  after the engines bump to >=22 in #46's chore commit.
- pg-node/src/config.mjs comment referenced `--env-file=` but the npm
  scripts use `--env-file-if-exists`.
- pg-node/README "Two modes" list used the inline-header + em-dash
  pattern flagged by writing-rules; converted to a small table.
- Trimmed a few stylistic em-dashes (lead paragraph, prerequisites,
  staging note, SDK-mapping paragraph). Kept the bold "does not
  actually deliver notification emails" callout — that one is
  load-bearing.

No behaviour change; verified with `node --check` on all .mjs files
and a live `npm run upload` to staging (UUID 6e22edaf-…).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant