@push.rocks/smartacme 9.1.1 → 9.1.2

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.
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartacme',
6
- version: '9.1.1',
6
+ version: '9.1.2',
7
7
  description: 'A TypeScript-based ACME client for LetsEncrypt certificate management with a focus on simplicity and power.'
8
8
  };
9
9
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx1QkFBdUI7SUFDN0IsT0FBTyxFQUFFLE9BQU87SUFDaEIsV0FBVyxFQUFFLDZHQUE2RztDQUMzSCxDQUFBIn0=
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@push.rocks/smartacme",
3
- "version": "9.1.1",
3
+ "version": "9.1.2",
4
4
  "private": false,
5
5
  "description": "A TypeScript-based ACME client for LetsEncrypt certificate management with a focus on simplicity and power.",
6
6
  "main": "dist_ts/index.js",
package/readme.md CHANGED
@@ -16,7 +16,7 @@ Ensure your project uses TypeScript and ECMAScript Modules (ESM).
16
16
 
17
17
  ## Usage
18
18
 
19
- `@push.rocks/smartacme` automates the full ACME certificate lifecycle — obtaining, renewing, and storing SSL/TLS certificates from Let's Encrypt. It features a built-in RFC 8555-compliant ACME protocol implementation, pluggable challenge handlers (DNS-01, HTTP-01), pluggable certificate storage backends (MongoDB, in-memory, or your own), and structured error handling with smart retry logic.
19
+ `@push.rocks/smartacme` automates the full ACME certificate lifecycle — obtaining, renewing, and storing SSL/TLS certificates from Let's Encrypt. It features a built-in RFC 8555-compliant ACME protocol implementation, pluggable challenge handlers (DNS-01, HTTP-01), pluggable certificate storage backends (MongoDB, in-memory, or your own), structured error handling with smart retry logic, and built-in concurrency control with rate limiting to keep you safely within Let's Encrypt limits.
20
20
 
21
21
  ### 🚀 Quick Start
22
22
 
@@ -58,18 +58,22 @@ await smartAcme.stop();
58
58
 
59
59
  ```typescript
60
60
  interface ISmartAcmeOptions {
61
- accountEmail: string; // ACME account email
62
- accountPrivateKey?: string; // Optional account key (auto-generated if omitted)
63
- certManager: ICertManager; // Certificate storage backend
61
+ accountEmail: string; // ACME account email
62
+ accountPrivateKey?: string; // Optional account key (auto-generated if omitted)
63
+ certManager: ICertManager; // Certificate storage backend
64
64
  environment: 'production' | 'integration'; // Let's Encrypt environment
65
- challengeHandlers: IChallengeHandler[]; // At least one handler required
66
- challengePriority?: string[]; // e.g. ['dns-01', 'http-01']
67
- retryOptions?: { // Optional retry/backoff config
68
- retries?: number; // Default: 10
69
- factor?: number; // Default: 4
70
- minTimeoutMs?: number; // Default: 1000
71
- maxTimeoutMs?: number; // Default: 60000
65
+ challengeHandlers: IChallengeHandler[]; // At least one handler required
66
+ challengePriority?: string[]; // e.g. ['dns-01', 'http-01']
67
+ retryOptions?: { // Optional retry/backoff config
68
+ retries?: number; // Default: 10
69
+ factor?: number; // Default: 4
70
+ minTimeoutMs?: number; // Default: 1000
71
+ maxTimeoutMs?: number; // Default: 60000
72
72
  };
73
+ // Concurrency & rate limiting
74
+ maxConcurrentIssuances?: number; // Global cap on parallel ACME ops (default: 5)
75
+ maxOrdersPerWindow?: number; // Max orders in sliding window (default: 250)
76
+ orderWindowMs?: number; // Sliding window duration in ms (default: 3 hours)
73
77
  }
74
78
  ```
75
79
 
@@ -112,6 +116,72 @@ cert.isStillValid(); // true if not expired
112
116
  cert.shouldBeRenewed(); // true if expires within 10 days
113
117
  ```
114
118
 
119
+ ## 🔀 Concurrency Control & Rate Limiting
120
+
121
+ When many callers request certificates concurrently (e.g., hundreds of subdomains under the same TLD), SmartAcme automatically handles deduplication, concurrency, and rate limiting using a built-in task manager powered by `@push.rocks/taskbuffer`.
122
+
123
+ ### How It Works
124
+
125
+ Three constraint layers protect your ACME account:
126
+
127
+ | Layer | What It Does | Default |
128
+ |-------|-------------|---------|
129
+ | **Per-domain mutex** | Only one issuance runs per base domain at a time. Concurrent requests for the same domain automatically wait and receive the same certificate result. | 1 concurrent per domain |
130
+ | **Global concurrency cap** | Limits total parallel ACME operations across all domains. | 5 concurrent |
131
+ | **Account rate limit** | Sliding-window rate limiter that keeps you under Let's Encrypt's 300 orders/3h account limit. | 250 per 3 hours |
132
+
133
+ ### 🛡️ Automatic Request Deduplication
134
+
135
+ If 100 requests come in for subdomains of `example.com` simultaneously, only **one** ACME issuance runs. All other callers automatically wait and receive the same certificate — no duplicate orders, no wasted rate limit budget.
136
+
137
+ ```typescript
138
+ // These all resolve to the same certificate with a single ACME order:
139
+ const results = await Promise.all([
140
+ smartAcme.getCertificateForDomain('app.example.com'),
141
+ smartAcme.getCertificateForDomain('api.example.com'),
142
+ smartAcme.getCertificateForDomain('cdn.example.com'),
143
+ ]);
144
+ ```
145
+
146
+ ### ⚡ Configuring Limits
147
+
148
+ ```typescript
149
+ const smartAcme = new SmartAcme({
150
+ accountEmail: 'admin@example.com',
151
+ certManager,
152
+ environment: 'production',
153
+ challengeHandlers: [dnsHandler],
154
+ maxConcurrentIssuances: 10, // Allow up to 10 parallel ACME issuances
155
+ maxOrdersPerWindow: 200, // Cap at 200 orders per window
156
+ orderWindowMs: 2 * 60 * 60_000, // 2-hour sliding window
157
+ });
158
+ ```
159
+
160
+ ### 📊 Observing Issuance Progress
161
+
162
+ Subscribe to the `certIssuanceEvents` stream to observe certificate issuance progress in real-time:
163
+
164
+ ```typescript
165
+ smartAcme.certIssuanceEvents.subscribe((event) => {
166
+ switch (event.type) {
167
+ case 'started':
168
+ console.log(`🔄 Issuance started: ${event.task.name}`);
169
+ break;
170
+ case 'step':
171
+ console.log(`📍 Step: ${event.stepName} (${event.task.currentProgress}%)`);
172
+ break;
173
+ case 'completed':
174
+ console.log(`✅ Issuance completed: ${event.task.name}`);
175
+ break;
176
+ case 'failed':
177
+ console.log(`❌ Issuance failed: ${event.error}`);
178
+ break;
179
+ }
180
+ });
181
+ ```
182
+
183
+ Each issuance goes through four steps: **prepare** (10%) → **authorize** (40%) → **finalize** (30%) → **store** (20%).
184
+
115
185
  ## Certificate Managers
116
186
 
117
187
  SmartAcme uses the `ICertManager` interface for pluggable certificate storage.
@@ -314,6 +384,7 @@ Under the hood, SmartAcme uses a fully custom RFC 8555-compliant ACME protocol i
314
384
  | `AcmeError` | Structured error class with type URN, subproblems, Retry-After, retryability |
315
385
  | `AcmeOrderManager` | Order lifecycle — create, poll, finalize, download certificate |
316
386
  | `AcmeChallengeManager` | Key authorization computation and challenge completion |
387
+ | `TaskManager` | Constraint-based concurrency control, rate limiting, and request deduplication via `@push.rocks/taskbuffer` |
317
388
 
318
389
  All cryptographic operations use `node:crypto`. The only external crypto dependency is `@peculiar/x509` for CSR generation.
319
390
 
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartacme',
6
- version: '9.1.1',
6
+ version: '9.1.2',
7
7
  description: 'A TypeScript-based ACME client for LetsEncrypt certificate management with a focus on simplicity and power.'
8
8
  }