diff --git a/changelog.md b/changelog.md index e4193cc..20795bd 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,13 @@ # Changelog +## 2025-05-01 - 7.2.2 - fix(readme) +Update readme documentation: switch installation instructions to pnpm and clarify usage with MongoCertManager and updated SmartAcme options + +- Replaced npm/yarn commands with pnpm commands for installation and testing. +- Added guidance to ensure the project is set up for TypeScript and ECMAScript Modules. +- Updated usage examples to include initialization of MongoCertManager instead of legacy mongoDescriptor. +- Revised challenge handlers examples to reference the current API signatures. + ## 2025-05-01 - 7.2.1 - fix(smartacme) Centralize interest map coordination and remove redundant interestMap from cert managers diff --git a/readme.md b/readme.md index c511300..48bc9ae 100644 --- a/readme.md +++ b/readme.md @@ -4,19 +4,26 @@ A TypeScript-based ACME client with an easy yet powerful interface for LetsEncry ## Install -To install `@push.rocks/smartacme`, you can use npm or yarn. Run one of the following commands in your project directory: +Using pnpm as the package manager: ```bash -npm install @push.rocks/smartacme --save +pnpm add @push.rocks/smartacme ``` -or +Ensure your project is set up to use TypeScript and ECMAScript Modules (ESM). +## Running Tests + +Tests are written using `@push.rocks/tapbundle` and can be run with: ```bash -yarn add @push.rocks/smartacme +pnpm test ``` -Make sure your project is set up to use TypeScript and supports ECMAScript Modules (ESM). +To run a specific test file: + +```bash +tsx test/.ts +``` ## Usage @@ -42,28 +49,31 @@ Ensure your project includes the necessary TypeScript configuration and dependen Start by importing the `SmartAcme` class and any built-in handlers you plan to use. For example, to use DNS-01 via Cloudflare: ```typescript -import { SmartAcme } from '@push.rocks/smartacme'; +import { SmartAcme, MongoCertManager } from '@push.rocks/smartacme'; import * as cloudflare from '@apiclient.xyz/cloudflare'; import { Dns01Handler } from '@push.rocks/smartacme/ts/handlers/Dns01Handler.js'; // Create a Cloudflare account client with your API token const cfAccount = new cloudflare.CloudflareAccount('YOUR_CF_TOKEN'); -// Instantiate SmartAcme with one or more ACME challenge handlers +// Initialize a certificate manager (e.g., MongoDB) +const certManager = new MongoCertManager({ + mongoDbUrl: 'mongodb://yourmongoURL', + mongoDbName: 'yourDbName', + mongoDbPass: 'yourDbPassword', +}); + +// Instantiate SmartAcme with the certManager and challenge handlers const smartAcmeInstance = new SmartAcme({ accountEmail: 'youremail@example.com', - mongoDescriptor: { - mongoDbUrl: 'mongodb://yourmongoURL', - mongoDbName: 'yourDbName', - mongoDbPass: 'yourDbPassword', - }, + certManager, environment: 'integration', // 'production' to request real certificates - retryOptions: {}, // optional retry/backoff settings - challengeHandlers: [ + retryOptions: {}, // optional retry/backoff settings + challengeHandlers: [ // pluggable ACME challenge handlers new Dns01Handler(cfAccount), - // you can add more handlers, e.g. Http01Webroot + // add more handlers as needed (e.g., Http01Webroot, Http01MemoryHandler) ], - challengePriority: ['dns-01'], // optional ordering of challenge types + challengePriority: ['dns-01'], // optional challenge ordering }); ``` @@ -91,14 +101,16 @@ SmartAcme uses pluggable ACME challenge handlers (see built-in handlers below) t ### Managing Certificates -The library automatically handles fetching, renewing, and storing your certificates in a MongoDB database specified in your configuration. Ensure your MongoDB instance is accessible and properly configured for use with SmartAcme. +The library automatically handles fetching, renewing, and storing your certificates in a MongoDB database specified via a certificate manager. Ensure your MongoDB instance is accessible and properly configured for use with SmartAcme. ```typescript -const mongoDescriptor = { +import { MongoCertManager } from '@push.rocks/smartacme'; + +const certManager = new MongoCertManager({ mongoDbUrl: 'mongodb://yourmongoURL', mongoDbName: 'yourDbName', mongoDbPass: 'yourDbPassword', -}; +}); ``` ### Environmental Considerations @@ -110,23 +122,27 @@ When creating an instance of `SmartAcme`, you can specify an `environment` optio Below is a complete example demonstrating how to use `@push.rocks/smartacme` to obtain and manage an ACME certificate with Let's Encrypt using a DNS-01 handler: ```typescript -import { SmartAcme } from '@push.rocks/smartacme'; +import { SmartAcme, MongoCertManager } from '@push.rocks/smartacme'; import * as cloudflare from '@apiclient.xyz/cloudflare'; import { Qenv } from '@push.rocks/qenv'; +import { Dns01Handler } from '@push.rocks/smartacme/ts/handlers/Dns01Handler.js'; const qenv = new Qenv('./', './.nogit/'); const cloudflareAccount = new cloudflare.CloudflareAccount(qenv.getEnvVarOnDemand('CF_TOKEN')); async function main() { + // Initialize MongoDB certificate manager + const certManager = new MongoCertManager({ + mongoDbUrl: qenv.getEnvVarRequired('MONGODB_URL'), + mongoDbName: qenv.getEnvVarRequired('MONGODB_DATABASE'), + mongoDbPass: qenv.getEnvVarRequired('MONGODB_PASSWORD'), + }); + const smartAcmeInstance = new SmartAcme({ accountEmail: 'youremail@example.com', - mongoDescriptor: { - mongoDbUrl: qenv.getEnvVarRequired('MONGODB_URL'), - mongoDbName: qenv.getEnvVarRequired('MONGODB_DATABASE'), - mongoDbPass: qenv.getEnvVarRequired('MONGODB_PASSWORD'), - }, + certManager, environment: 'integration', - challengeHandlers: [ new Dns01Handler(cloudflareAccount) ], + challengeHandlers: [new Dns01Handler(cloudflareAccount)], }); await smartAcmeInstance.start(); @@ -138,8 +154,8 @@ async function main() { await smartAcmeInstance.stop(); } - main().catch(console.error); - ``` +main().catch(console.error); +``` ## Built-in Challenge Handlers @@ -222,7 +238,7 @@ async function main() { challengePriority: ['my-01'], }); -In this example, `Qenv` is used to manage environment variables, and `cloudflare` library is used to handle DNS challenges required by Let's Encrypt ACME protocol. The `setChallenge` and `removeChallenge` methods are essential for automating the DNS challenge process, which is a key part of domain validation. +In this example, `Qenv` is used to manage environment variables, and the Cloudflare library is used to handle DNS challenges through the built-in `Dns01Handler` plugin. ## Additional Details @@ -243,8 +259,6 @@ The certificate object obtained from the `getCertificateForDomain` method has th - **start()**: Initializes the SmartAcme instance, sets up the ACME client, and registers the account with Let's Encrypt. - **stop()**: Closes the MongoDB connection and performs any necessary cleanup. - **getCertificateForDomain(domainArg: string)**: Retrieves or obtains a certificate for the specified domain name. If a valid certificate exists in the database, it is returned. Otherwise, a new certificate is requested and stored. -- **setChallenge(dnsChallenge: any)**: Automates the process of setting DNS challenge records. -- **removeChallenge(dnsChallenge: any)**: Automates the process of removing DNS challenge records. ### Handling Domain Matching @@ -260,60 +274,13 @@ console.log('Certificate Domain Name:', certDomainName); // Output: example.com ### Testing -Automated tests can be added to ensure that the setup and functions work as expected. Using a testing framework such as `tap` and mock services for DNS providers (e.g., Cloudflare), you can simulate the process of obtaining and managing certificates without the need for actual domain ownership. +Sample tests are provided in the `test` directory. They demonstrate core functionality using the `MemoryCertManager` and built-in challenge handlers. To run all tests, use: -```typescript -import { tap, expect } from '@push.rocks/tapbundle'; -import { Qenv } from '@push.rocks/qenv'; -import * as cloudflare from '@apiclient.xyz/cloudflare'; -import * as smartacme from '@push.rocks/smartacme'; - -const testQenv = new Qenv('./', './.nogit/'); -const testCloudflare = new cloudflare.CloudflareAccount(testQenv.getEnvVarOnDemand('CF_TOKEN')); - -let smartAcmeInstance: smartacme.SmartAcme; - -tap.test('should create a valid instance of SmartAcme', async () => { - smartAcmeInstance = new smartacme.SmartAcme({ - accountEmail: 'domains@lossless.org', - accountPrivateKey: null, - mongoDescriptor: { - mongoDbName: testQenv.getEnvVarRequired('MONGODB_DATABASE'), - mongoDbPass: testQenv.getEnvVarRequired('MONGODB_PASSWORD'), - mongoDbUrl: testQenv.getEnvVarRequired('MONGODB_URL'), - }, - setChallenge: async (dnsChallenge) => { - await testCloudflare.convenience.acmeSetDnsChallenge(dnsChallenge); - }, - removeChallenge: async (dnsChallenge) => { - await testCloudflare.convenience.acmeRemoveDnsChallenge(dnsChallenge); - }, - environment: 'integration', - }); - await smartAcmeInstance.init(); - expect(smartAcmeInstance).toBeInstanceOf(smartacme.SmartAcme); -}); - -tap.test('should get a domain certificate', async () => { - const certificate = await smartAcmeInstance.getCertificateForDomain('example.com'); - console.log('Certificate:', certificate); - expect(certificate).toHaveProperty('domainName', 'example.com'); -}); - -tap.test('certmatcher should correctly match domains', async () => { - const certMatcher = new smartacme.SmartacmeCertMatcher(); - const matchedCert = certMatcher.getCertificateDomainNameByDomainName('subdomain.example.com'); - expect(matchedCert).toBe('example.com'); -}); - -tap.test('should stop correctly', async () => { - await smartAcmeInstance.stop(); - expect(smartAcmeInstance).toHaveProperty('client', null); -}); - -tap.start(); +```bash +pnpm test ``` + This comprehensive guide ensures you can set up, manage, and test ACME certificates efficiently and effectively using `@push.rocks/smartacme`. --- diff --git a/ts/00_commitinfo_data.ts b/ts/00_commitinfo_data.ts index 98ddb2b..44956e0 100644 --- a/ts/00_commitinfo_data.ts +++ b/ts/00_commitinfo_data.ts @@ -3,6 +3,6 @@ */ export const commitinfo = { name: '@push.rocks/smartacme', - version: '7.2.1', + version: '7.2.2', description: 'A TypeScript-based ACME client for LetsEncrypt certificate management with a focus on simplicity and power.' }