@postalsys/certs 1.0.12 → 1.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,7 +18,7 @@ jobs:
18
18
  with:
19
19
  release-type: node
20
20
  package-name: ${{vars.NPM_MODULE_NAME}}
21
- pull-request-title-pattern: 'chore${scope}: release ${version} [skip-ci]'
21
+ pull-request-title-pattern: "chore${scope}: release ${version} [skip-ci]"
22
22
  # The logic below handles the npm publication:
23
23
  - uses: actions/checkout@v3
24
24
  # these if statements ensure that a publication only occurs when
@@ -26,12 +26,10 @@ jobs:
26
26
  if: ${{ steps.release.outputs.release_created }}
27
27
  - uses: actions/setup-node@v3
28
28
  with:
29
- node-version: 18
30
- registry-url: 'https://registry.npmjs.org'
29
+ node-version: 24
30
+ registry-url: "https://registry.npmjs.org"
31
31
  if: ${{ steps.release.outputs.release_created }}
32
32
  - run: npm ci
33
33
  if: ${{ steps.release.outputs.release_created }}
34
34
  - run: npm publish --provenance --access public
35
- env:
36
- NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
37
35
  if: ${{ steps.release.outputs.release_created }}
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.0.13](https://github.com/postalsys/certs/compare/v1.0.12...v1.0.13) (2026-03-23)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * bumped deos ([3d8cc4c](https://github.com/postalsys/certs/commit/3d8cc4ce6f5a58c25f9780076dc8adc99f26d279))
9
+ * update release workflow to Node 24 and use trusted publishers ([2392f54](https://github.com/postalsys/certs/commit/2392f547f421bbf83f32ffe4e06cbbf3f4cfc80c))
10
+
3
11
  ## [1.0.12](https://github.com/postalsys/certs/compare/v1.0.11...v1.0.12) (2025-09-29)
4
12
 
5
13
 
package/README.md ADDED
@@ -0,0 +1,122 @@
1
+ # @postalsys/certs
2
+
3
+ Manage Let's Encrypt SSL/TLS certificates with automatic acquisition, renewal, and storage via the ACME protocol. Certificates and ACME account data are stored in Redis. Supports ACME HTTP-01 challenges.
4
+
5
+ ## Installation
6
+
7
+ ```
8
+ npm install @postalsys/certs
9
+ ```
10
+
11
+ **Requirements:** Node.js 15+ (for CAA record validation), Redis
12
+
13
+ ## Usage
14
+
15
+ ```js
16
+ const Redis = require('ioredis');
17
+ const express = require('express');
18
+ const { Certs } = require('@postalsys/certs');
19
+
20
+ const redis = new Redis();
21
+ const app = express();
22
+
23
+ const certs = new Certs({
24
+ redis,
25
+ namespace: 'myapp',
26
+
27
+ acme: {
28
+ // Use 'production' and the production directory URL for real certificates
29
+ environment: 'production',
30
+ directoryUrl: 'https://acme-v02.api.letsencrypt.org/directory',
31
+ email: 'admin@example.com'
32
+ },
33
+
34
+ // Optional: encrypt private keys before storing in Redis
35
+ encryptFn: async (value) => {
36
+ // your encryption logic
37
+ return encryptedValue;
38
+ },
39
+ decryptFn: async (value) => {
40
+ // your decryption logic
41
+ return decryptedValue;
42
+ }
43
+ });
44
+
45
+ // Retrieve or acquire a certificate
46
+ const certData = await certs.getCertificate('example.com');
47
+ // certData.cert - PEM certificate
48
+ // certData.privateKey - PEM private key
49
+ // certData.ca - array of CA chain certificates
50
+ // certData.validTo - expiration date
51
+
52
+ // ACME HTTP-01 challenge handler
53
+ app.get('/.well-known/acme-challenge/:token', (req, res) => {
54
+ const token = req.params.token;
55
+ const domain = req.get('host');
56
+ certs
57
+ .routeHandler(domain, token)
58
+ .then(challenge => {
59
+ res.status(200).set('content-type', 'text/plain').send(challenge);
60
+ })
61
+ .catch(err => {
62
+ res.status(err.responseCode || 500).send({
63
+ error: err.message,
64
+ code: err.code
65
+ });
66
+ });
67
+ });
68
+ ```
69
+
70
+ ## Constructor Options
71
+
72
+ | Option | Type | Default | Description |
73
+ |--------|------|---------|-------------|
74
+ | `redis` | Object | *required* | ioredis (or compatible) client instance |
75
+ | `namespace` | String | `undefined` | Key prefix for Redis storage |
76
+ | `encryptFn` | Function | identity | Async function to encrypt private keys before storage |
77
+ | `decryptFn` | Function | identity | Async function to decrypt private keys after retrieval |
78
+ | `acme.environment` | String | `'development'` | `'development'` (staging) or `'production'` |
79
+ | `acme.directoryUrl` | String | LE staging URL | ACME directory URL |
80
+ | `acme.email` | String | | Subscriber email for the ACME account |
81
+ | `acme.caaDomains` | Array | `['letsencrypt.org']` | Allowed CAA record domains |
82
+ | `acme.keyBits` | Number | `2048` | RSA key size for ACME account key |
83
+ | `acme.keyExponent` | Number | `65537` | RSA public exponent for ACME account key |
84
+ | `keyBits` | Number | `2048` | RSA key size for domain certificates |
85
+ | `keyExponent` | Number | `65537` | RSA public exponent for domain certificates |
86
+ | `logger` | Object | pino instance | Logger (pino-compatible) |
87
+
88
+ ## API
89
+
90
+ ### `Certs.create(options)`
91
+
92
+ Static factory method. Returns a new `Certs` instance.
93
+
94
+ ### `getCertificate(domain, skipAcquire?)`
95
+
96
+ Returns stored certificate data for the domain. If the certificate is missing or expired, automatically acquires a new one via ACME unless `skipAcquire` is `true`.
97
+
98
+ Returns an object with `cert`, `privateKey`, `ca`, `validFrom`, `validTo`, `altNames`, `serialNumber`, `fingerprint`, `status`, and `lastError`, or `false` if no certificate exists.
99
+
100
+ ### `acquireCert(domain)`
101
+
102
+ Forces certificate acquisition or renewal for the domain. Validates the domain name and CAA records, obtains a distributed lock, generates a CSR, and requests a certificate via ACME HTTP-01 challenge. Falls back to existing certificate data on error.
103
+
104
+ ### `routeHandler(domain, token)`
105
+
106
+ Resolves an ACME HTTP-01 challenge. Use this as the handler for `GET /.well-known/acme-challenge/:token` requests. Returns the `keyAuthorization` string on success or throws with a `responseCode` property on failure.
107
+
108
+ ### `listCertificateDomains()`
109
+
110
+ Returns a sorted array of all domain names that have certificate records.
111
+
112
+ ### `deleteCertificateData(domain)`
113
+
114
+ Removes all stored certificate data for the domain.
115
+
116
+ ## Automatic Renewal
117
+
118
+ Certificates are automatically renewed when retrieved via `getCertificate()` if they expire within 30 days. After a failed renewal attempt, a short safety lock prevents repeated retries.
119
+
120
+ ## License
121
+
122
+ ISC
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postalsys/certs",
3
- "version": "1.0.12",
3
+ "version": "1.0.13",
4
4
  "description": "Manage Let's Encrypt certificates",
5
5
  "main": "lib/certs.js",
6
6
  "scripts": {
@@ -21,15 +21,15 @@
21
21
  "eslint-config-nodemailer": "1.2.0",
22
22
  "eslint-config-prettier": "9.1.0",
23
23
  "express": "4.19.2",
24
- "ioredis": "5.8.0"
24
+ "ioredis": "5.10.1"
25
25
  },
26
26
  "dependencies": {
27
27
  "@root/acme": "3.1.0",
28
- "ioredfour": "1.3.0-ioredis-07",
29
- "joi": "18.0.1",
28
+ "ioredfour": "1.4.0",
29
+ "joi": "18.0.2",
30
30
  "msgpack5": "6.0.2",
31
31
  "pem-jwk": "2.0.0",
32
- "pino": "9.12.0",
32
+ "pino": "10.3.1",
33
33
  "punycode.js": "2.3.1"
34
34
  }
35
35
  }