- this repo is dependent on letsencrypt and its limits - to simpify the outside API, smartacme is stateful, meaning it works with a mongodb and a collection called 'SmartacmeCert'. ## Certificate Request Behavior As of v7.4.0, SmartAcme no longer automatically requests wildcard certificates for all domain requests. This change was made to fix issues with HTTP-01 only configurations which cannot validate wildcard domains. - By default, `getCertificateForDomain('example.com')` only requests a certificate for `example.com` - To request both regular and wildcard certificates, use `getCertificateForDomain('example.com', { includeWildcard: true })` - Wildcard certificates require a DNS-01 challenge handler to be configured - Direct wildcard requests like `getCertificateForDomain('*.example.com')` only request the wildcard certificate This change ensures HTTP-01 only configurations work properly while still allowing wildcard certificates when needed and supported. ## ACME Protocol Implementation As of v8.1.0, the `acme-client` npm package has been replaced with a custom OOP implementation under `ts/acme/`. This uses `node:crypto` for all cryptographic operations and `@peculiar/x509` solely for CSR generation. The implementation follows RFC 8555. Key files: - `ts/acme/acme.classes.client.ts` — Top-level facade (`AcmeClient`), accepts optional `logger` callback - `ts/acme/acme.classes.crypto.ts` — Key gen, JWK, JWS signing, CSR (`AcmeCrypto`) - `ts/acme/acme.classes.http-client.ts` — JWS-signed HTTP transport with nonce management and logging - `ts/acme/acme.classes.error.ts` — Structured `AcmeError` with type URN, subproblems, Retry-After, `isRetryable`/`isRateLimited` - `ts/acme/acme.classes.account.ts` — Account registration - `ts/acme/acme.classes.order.ts` — Order lifecycle + polling - `ts/acme/acme.classes.challenge.ts` — Key authorization + challenge completion - `ts/acme/acme.classes.directory.ts` — CA directory URL constants (`ACME_DIRECTORY_URLS`) Usage in `ts/plugins.ts`: `import * as acme from './acme/index.js'` (replaces `acme-client`) ## Concurrency & Rate Limiting (taskbuffer integration) As of v9.1.0, `@push.rocks/lik.InterestMap` was replaced with `@push.rocks/taskbuffer.TaskManager` for coordinating concurrent certificate requests. This provides: - **Per-domain mutex** (`cert-domain-mutex`): Only one ACME issuance per TLD at a time, with `resultSharingMode: 'share-latest'` so queued callers get the same result without re-issuing. - **Global concurrency cap** (`acme-global-concurrency`): Limits total parallel ACME operations (default 5, configurable via `maxConcurrentIssuances`). - **Account-level rate limiting** (`acme-account-rate-limit`): Sliding-window rate limit (default 250 orders per 3 hours, configurable via `maxOrdersPerWindow`/`orderWindowMs`) to stay under Let's Encrypt limits. - **Step-based progress**: The cert issuance task uses `notifyStep()` for prepare/authorize/finalize/store phases, observable via `smartAcme.certIssuanceEvents`. Key implementation details: - A single reusable `Task` named `cert-issuance` handles all domains via `triggerTaskConstrained()` with different inputs. - The `shouldExecute` callback on the domain mutex checks the certmanager cache as a safety net. - `TaskManager.start()` is called in `SmartAcme.start()` and `TaskManager.stop()` in `SmartAcme.stop()`. - The "no cronjobs specified" log messages during tests come from taskbuffer's internal CronManager polling — harmless noise when no cron tasks are scheduled. ## ACME Directory Server (ts_server/) As of v9.2.0, a built-in ACME Directory Server lives under `ts_server/`. This is a full RFC 8555-compliant CA server that allows running your own Certificate Authority. Key files: - `ts_server/server.classes.acmeserver.ts` — Top-level `AcmeServer` facade (start/stop/config) - `ts_server/server.classes.ca.ts` — Self-signed root CA generation + certificate signing via `@peculiar/x509` - `ts_server/server.classes.jws.verifier.ts` — JWS signature verification (inverse of `AcmeCrypto.createJws`) - `ts_server/server.classes.router.ts` — Minimal HTTP router with `:param` support using raw `node:http` - `ts_server/server.classes.nonce.ts` — Single-use replay nonce management - `ts_server/server.classes.challenge.verifier.ts` — HTTP-01/DNS-01 verification (with bypass mode) - `ts_server/server.classes.account.store.ts` — In-memory account storage - `ts_server/server.classes.order.store.ts` — In-memory order/authz/challenge/cert storage - `ts_server/server.handlers.*.ts` — Route handlers for each ACME endpoint Design decisions: - Uses raw `node:http` (no framework dependency — `@api.global/typedserver` was explicitly removed in v8.1.0) - Zero new dependencies: uses `node:crypto`, `@peculiar/x509`, and existing project deps - Reuses `AcmeCrypto` for JWK thumbprint/base64url, ACME interfaces for response types, `AcmeError` patterns - `AcmeCrypto.getAlg()` was made public (was private) for use by the JWS verifier - Storage interfaces (`IServerAccountStore`, `IServerOrderStore`) are pluggable, with in-memory defaults - `challengeVerification: false` option auto-approves challenges for testing - `tsbuild tsfolders` automatically compiles `ts_server/` to `dist_ts_server/` ## Dependency Notes - `acme-client` was replaced with custom implementation in `ts/acme/` + `@peculiar/x509` for CSR generation - `@push.rocks/smartfile`, `@api.global/typedserver`, `@push.rocks/smartrequest`, `@push.rocks/smartpromise` were removed as unused dependencies in v8.1.0 - The `@apiclient.xyz/cloudflare` `convenience` namespace is deprecated but still functional. The `Dns01Handler` accepts an `IConvenientDnsProvider` interface which remains stable. - Test imports use `@git.zone/tstest/tapbundle` (not `@push.rocks/tapbundle`) - Build uses `tsbuild tsfolders` (v4.3.0+) — auto-discovers and compiles `ts/` and `ts_server/` directories