@push.rocks/smartacme 6.1.2 → 6.2.0

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: '6.1.2',
6
+ version: '6.2.0',
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=
@@ -6,8 +6,9 @@ import type { IChallengeHandler } from './IChallengeHandler.js';
6
6
  export declare class Dns01Handler implements IChallengeHandler<plugins.tsclass.network.IDnsChallenge> {
7
7
  private cf;
8
8
  private smartdns;
9
- constructor(cloudflareAccount: any, smartdnsInstance?: plugins.smartdnsClient.Smartdns);
9
+ constructor(convenientDnsProvider: plugins.tsclass.network.IConvenientDnsProvider, smartdnsInstance?: plugins.smartdnsClient.Smartdns);
10
10
  getSupportedTypes(): string[];
11
11
  prepare(ch: plugins.tsclass.network.IDnsChallenge): Promise<void>;
12
12
  cleanup(ch: plugins.tsclass.network.IDnsChallenge): Promise<void>;
13
+ checkWetherDomainIsSupported(domainArg: string): Promise<boolean>;
13
14
  }
@@ -3,8 +3,8 @@ import * as plugins from '../smartacme.plugins.js';
3
3
  * DNS-01 challenge handler using CloudflareAccount and Smartdns.
4
4
  */
5
5
  export class Dns01Handler {
6
- constructor(cloudflareAccount, smartdnsInstance) {
7
- this.cf = cloudflareAccount;
6
+ constructor(convenientDnsProvider, smartdnsInstance) {
7
+ this.cf = convenientDnsProvider;
8
8
  this.smartdns = smartdnsInstance ?? new plugins.smartdnsClient.Smartdns({});
9
9
  }
10
10
  getSupportedTypes() {
@@ -20,5 +20,8 @@ export class Dns01Handler {
20
20
  // remove DNS TXT record
21
21
  await this.cf.convenience.acmeRemoveDnsChallenge(ch);
22
22
  }
23
+ async checkWetherDomainIsSupported(domainArg) {
24
+ return this.cf.convenience.isDomainSupported(domainArg);
25
+ }
23
26
  }
24
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRG5zMDFIYW5kbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvaGFuZGxlcnMvRG5zMDFIYW5kbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0seUJBQXlCLENBQUM7QUFHbkQ7O0dBRUc7QUFDSCxNQUFNLE9BQU8sWUFBWTtJQUl2QixZQUNFLGlCQUFzQixFQUN0QixnQkFBa0Q7UUFFbEQsSUFBSSxDQUFDLEVBQUUsR0FBRyxpQkFBaUIsQ0FBQztRQUM1QixJQUFJLENBQUMsUUFBUSxHQUFHLGdCQUFnQixJQUFJLElBQUksT0FBTyxDQUFDLGNBQWMsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDOUUsQ0FBQztJQUVNLGlCQUFpQjtRQUN0QixPQUFPLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDcEIsQ0FBQztJQUVNLEtBQUssQ0FBQyxPQUFPLENBQUMsRUFBeUM7UUFDNUQscUJBQXFCO1FBQ3JCLE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQyxXQUFXLENBQUMsbUJBQW1CLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDbEQsMkJBQTJCO1FBQzNCLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxtQkFBbUIsQ0FDckMsRUFBRSxDQUFDLFFBQVEsRUFDWCxLQUFLLEVBQ0wsRUFBRSxDQUFDLFNBQVMsRUFDWixHQUFHLEVBQ0gsSUFBSSxDQUNMLENBQUM7SUFDSixDQUFDO0lBRU0sS0FBSyxDQUFDLE9BQU8sQ0FBQyxFQUF5QztRQUM1RCx3QkFBd0I7UUFDeEIsTUFBTSxJQUFJLENBQUMsRUFBRSxDQUFDLFdBQVcsQ0FBQyxzQkFBc0IsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN2RCxDQUFDO0NBQ0YifQ==
27
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRG5zMDFIYW5kbGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHMvaGFuZGxlcnMvRG5zMDFIYW5kbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0seUJBQXlCLENBQUM7QUFHbkQ7O0dBRUc7QUFDSCxNQUFNLE9BQU8sWUFBWTtJQUl2QixZQUNFLHFCQUFxRSxFQUNyRSxnQkFBa0Q7UUFFbEQsSUFBSSxDQUFDLEVBQUUsR0FBRyxxQkFBcUIsQ0FBQztRQUNoQyxJQUFJLENBQUMsUUFBUSxHQUFHLGdCQUFnQixJQUFJLElBQUksT0FBTyxDQUFDLGNBQWMsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDOUUsQ0FBQztJQUVNLGlCQUFpQjtRQUN0QixPQUFPLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDcEIsQ0FBQztJQUVNLEtBQUssQ0FBQyxPQUFPLENBQUMsRUFBeUM7UUFDNUQscUJBQXFCO1FBQ3JCLE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQyxXQUFXLENBQUMsbUJBQW1CLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDbEQsMkJBQTJCO1FBQzNCLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxtQkFBbUIsQ0FDckMsRUFBRSxDQUFDLFFBQVEsRUFDWCxLQUFLLEVBQ0wsRUFBRSxDQUFDLFNBQVMsRUFDWixHQUFHLEVBQ0gsSUFBSSxDQUNMLENBQUM7SUFDSixDQUFDO0lBRU0sS0FBSyxDQUFDLE9BQU8sQ0FBQyxFQUF5QztRQUM1RCx3QkFBd0I7UUFDeEIsTUFBTSxJQUFJLENBQUMsRUFBRSxDQUFDLFdBQVcsQ0FBQyxzQkFBc0IsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN2RCxDQUFDO0lBRU0sS0FBSyxDQUFDLDRCQUE0QixDQUFDLFNBQWlCO1FBQ3pELE9BQU8sSUFBSSxDQUFDLEVBQUUsQ0FBQyxXQUFXLENBQUMsaUJBQWlCLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDMUQsQ0FBQztDQUNGIn0=
@@ -3,20 +3,20 @@ import type { IChallengeHandler } from './IChallengeHandler.js';
3
3
  * HTTP-01 ACME challenge handler using file-system webroot.
4
4
  * Writes and removes the challenge file under <webroot>/.well-known/acme-challenge/.
5
5
  */
6
- export interface Http01HandlerOptions {
6
+ export interface Http01WebrootOptions {
7
7
  /**
8
8
  * Directory that serves HTTP requests for /.well-known/acme-challenge
9
9
  */
10
10
  webroot: string;
11
11
  }
12
- export declare class Http01Handler implements IChallengeHandler<{
12
+ export declare class Http01Webroot implements IChallengeHandler<{
13
13
  type: string;
14
14
  token: string;
15
15
  keyAuthorization: string;
16
16
  webPath: string;
17
17
  }> {
18
18
  private webroot;
19
- constructor(options: Http01HandlerOptions);
19
+ constructor(options: Http01WebrootOptions);
20
20
  getSupportedTypes(): string[];
21
21
  prepare(ch: {
22
22
  token: string;
@@ -1,6 +1,6 @@
1
1
  import { promises as fs } from 'fs';
2
2
  import * as path from 'path';
3
- export class Http01Handler {
3
+ export class Http01Webroot {
4
4
  constructor(options) {
5
5
  this.webroot = options.webroot;
6
6
  }
@@ -0,0 +1,26 @@
1
+ import type { IChallengeHandler } from './IChallengeHandler.js';
2
+ /**
3
+ * HTTP-01 ACME challenge handler using in-memory storage.
4
+ * Stores challenge tokens and key authorizations in memory
5
+ * and serves them via handleRequest for arbitrary HTTP servers.
6
+ */
7
+ export interface Http01MemoryHandlerChallenge {
8
+ type: string;
9
+ token: string;
10
+ keyAuthorization: string;
11
+ webPath: string;
12
+ }
13
+ export declare class Http01MemoryHandler implements IChallengeHandler<Http01MemoryHandlerChallenge> {
14
+ private store;
15
+ getSupportedTypes(): string[];
16
+ prepare(ch: Http01MemoryHandlerChallenge): Promise<void>;
17
+ verify(_ch: Http01MemoryHandlerChallenge): Promise<void>;
18
+ cleanup(ch: Http01MemoryHandlerChallenge): Promise<void>;
19
+ /**
20
+ * HTTP request handler for serving ACME HTTP-01 challenges.
21
+ * @param req HTTP request object (should have url property)
22
+ * @param res HTTP response object
23
+ * @param next Optional next() callback for Express-style fallthrough
24
+ */
25
+ handleRequest(req: any, res: any, next?: () => void): void;
26
+ }
@@ -0,0 +1,51 @@
1
+ export class Http01MemoryHandler {
2
+ constructor() {
3
+ this.store = new Map();
4
+ }
5
+ getSupportedTypes() {
6
+ return ['http-01'];
7
+ }
8
+ async prepare(ch) {
9
+ this.store.set(ch.token, ch.keyAuthorization);
10
+ }
11
+ async verify(_ch) {
12
+ // No-op
13
+ return;
14
+ }
15
+ async cleanup(ch) {
16
+ this.store.delete(ch.token);
17
+ }
18
+ /**
19
+ * HTTP request handler for serving ACME HTTP-01 challenges.
20
+ * @param req HTTP request object (should have url property)
21
+ * @param res HTTP response object
22
+ * @param next Optional next() callback for Express-style fallthrough
23
+ */
24
+ handleRequest(req, res, next) {
25
+ const url = req.url || '';
26
+ const prefix = '/.well-known/acme-challenge/';
27
+ if (!url.startsWith(prefix)) {
28
+ if (next) {
29
+ return next();
30
+ }
31
+ res.statusCode = 404;
32
+ return res.end();
33
+ }
34
+ const token = url.slice(prefix.length);
35
+ const keyAuth = this.store.get(token);
36
+ if (keyAuth !== undefined) {
37
+ if (typeof res.status === 'function' && typeof res.send === 'function') {
38
+ return res.status(200).send(keyAuth);
39
+ }
40
+ res.statusCode = 200;
41
+ res.setHeader('content-type', 'text/plain');
42
+ return res.end(keyAuth);
43
+ }
44
+ if (next) {
45
+ return next();
46
+ }
47
+ res.statusCode = 404;
48
+ return res.end();
49
+ }
50
+ }
51
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiSHR0cDAxTWVtb3J5SGFuZGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2hhbmRsZXJzL0h0dHAwMU1lbW9yeUhhbmRsZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBY0EsTUFBTSxPQUFPLG1CQUFtQjtJQUFoQztRQUNVLFVBQUssR0FBd0IsSUFBSSxHQUFHLEVBQUUsQ0FBQztJQW1EakQsQ0FBQztJQWpEUSxpQkFBaUI7UUFDdEIsT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ3JCLENBQUM7SUFFTSxLQUFLLENBQUMsT0FBTyxDQUFDLEVBQWdDO1FBQ25ELElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLGdCQUFnQixDQUFDLENBQUM7SUFDaEQsQ0FBQztJQUVNLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBaUM7UUFDbkQsUUFBUTtRQUNSLE9BQU87SUFDVCxDQUFDO0lBRU0sS0FBSyxDQUFDLE9BQU8sQ0FBQyxFQUFnQztRQUNuRCxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDOUIsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ksYUFBYSxDQUFDLEdBQVEsRUFBRSxHQUFRLEVBQUUsSUFBaUI7UUFDeEQsTUFBTSxHQUFHLEdBQUcsR0FBRyxDQUFDLEdBQUcsSUFBSSxFQUFFLENBQUM7UUFDMUIsTUFBTSxNQUFNLEdBQUcsOEJBQThCLENBQUM7UUFDOUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztZQUM1QixJQUFJLElBQUksRUFBRSxDQUFDO2dCQUNULE9BQU8sSUFBSSxFQUFFLENBQUM7WUFDaEIsQ0FBQztZQUNELEdBQUcsQ0FBQyxVQUFVLEdBQUcsR0FBRyxDQUFDO1lBQ3JCLE9BQU8sR0FBRyxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBQ25CLENBQUM7UUFDRCxNQUFNLEtBQUssR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN2QyxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN0QyxJQUFJLE9BQU8sS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUMxQixJQUFJLE9BQU8sR0FBRyxDQUFDLE1BQU0sS0FBSyxVQUFVLElBQUksT0FBTyxHQUFHLENBQUMsSUFBSSxLQUFLLFVBQVUsRUFBRSxDQUFDO2dCQUN2RSxPQUFPLEdBQUcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ3ZDLENBQUM7WUFDRCxHQUFHLENBQUMsVUFBVSxHQUFHLEdBQUcsQ0FBQztZQUNyQixHQUFHLENBQUMsU0FBUyxDQUFDLGNBQWMsRUFBRSxZQUFZLENBQUMsQ0FBQztZQUM1QyxPQUFPLEdBQUcsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDMUIsQ0FBQztRQUNELElBQUksSUFBSSxFQUFFLENBQUM7WUFDVCxPQUFPLElBQUksRUFBRSxDQUFDO1FBQ2hCLENBQUM7UUFDRCxHQUFHLENBQUMsVUFBVSxHQUFHLEdBQUcsQ0FBQztRQUNyQixPQUFPLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUNuQixDQUFDO0NBQ0YifQ==
@@ -1,3 +1,4 @@
1
1
  export type { IChallengeHandler } from './IChallengeHandler.js';
2
2
  export { Dns01Handler } from './Dns01Handler.js';
3
- export { Http01Handler } from './Http01Handler.js';
3
+ export { Http01Webroot } from './Http01Handler.js';
4
+ export { Http01MemoryHandler } from './Http01MemoryHandler.js';
@@ -1,4 +1,5 @@
1
1
  // Removed legacy handler adapter
2
2
  export { Dns01Handler } from './Dns01Handler.js';
3
- export { Http01Handler } from './Http01Handler.js';
4
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9oYW5kbGVycy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxpQ0FBaUM7QUFDakMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQyJ9
3
+ export { Http01Webroot } from './Http01Handler.js';
4
+ export { Http01MemoryHandler } from './Http01MemoryHandler.js';
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90cy9oYW5kbGVycy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxpQ0FBaUM7QUFDakMsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNuRCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQyJ9
@@ -1,3 +1,5 @@
1
+ import * as cloudflare from '@apiclient.xyz/cloudflare';
2
+ export { cloudflare };
1
3
  import * as typedserver from '@api.global/typedserver';
2
4
  export { typedserver };
3
5
  import * as lik from '@push.rocks/lik';
@@ -1,3 +1,6 @@
1
+ // @apiclient.xyz scope
2
+ import * as cloudflare from '@apiclient.xyz/cloudflare';
3
+ export { cloudflare };
1
4
  // @apiglobal scope
2
5
  import * as typedserver from '@api.global/typedserver';
3
6
  export { typedserver };
@@ -22,4 +25,4 @@ export { acme };
22
25
  // local handlers for challenge types
23
26
  import * as handlers from './handlers/index.js';
24
27
  export { handlers };
25
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRhY21lLnBsdWdpbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydGFjbWUucGx1Z2lucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxtQkFBbUI7QUFDbkIsT0FBTyxLQUFLLFdBQVcsTUFBTSx5QkFBeUIsQ0FBQztBQUV2RCxPQUFPLEVBQUUsV0FBVyxFQUFFLENBQUM7QUFFdkIsbUJBQW1CO0FBQ25CLE9BQU8sS0FBSyxHQUFHLE1BQU0saUJBQWlCLENBQUM7QUFDdkMsT0FBTyxLQUFLLFNBQVMsTUFBTSx1QkFBdUIsQ0FBQztBQUNuRCxPQUFPLEtBQUssVUFBVSxNQUFNLHdCQUF3QixDQUFDO0FBQ3JELE9BQU8sS0FBSyxjQUFjLE1BQU0sNkJBQTZCLENBQUM7QUFDOUQsT0FBTyxLQUFLLFFBQVEsTUFBTSxzQkFBc0IsQ0FBQztBQUNqRCxPQUFPLEtBQUssWUFBWSxNQUFNLDBCQUEwQixDQUFDO0FBQ3pELE9BQU8sS0FBSyxZQUFZLE1BQU0sMEJBQTBCLENBQUM7QUFDekQsT0FBTyxLQUFLLFdBQVcsTUFBTSx5QkFBeUIsQ0FBQztBQUN2RCxPQUFPLEtBQUssV0FBVyxNQUFNLHlCQUF5QixDQUFDO0FBQ3ZELE9BQU8sS0FBSyxTQUFTLE1BQU0sdUJBQXVCLENBQUM7QUFFbkQsT0FBTyxFQUNMLEdBQUcsRUFDSCxTQUFTLEVBQ1QsVUFBVSxFQUNWLGNBQWMsRUFDZCxRQUFRLEVBQ1IsWUFBWSxFQUNaLFlBQVksRUFDWixXQUFXLEVBQ1gsV0FBVyxFQUNYLFNBQVMsR0FDVixDQUFDO0FBRUYsaUJBQWlCO0FBQ2pCLE9BQU8sS0FBSyxPQUFPLE1BQU0sa0JBQWtCLENBQUM7QUFFNUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxDQUFDO0FBRW5CLG9CQUFvQjtBQUNwQixPQUFPLEtBQUssSUFBSSxNQUFNLGFBQWEsQ0FBQztBQUVwQyxPQUFPLEVBQUUsSUFBSSxFQUFFLENBQUM7QUFDaEIscUNBQXFDO0FBQ3JDLE9BQU8sS0FBSyxRQUFRLE1BQU0scUJBQXFCLENBQUM7QUFDaEQsT0FBTyxFQUFFLFFBQVEsRUFBRSxDQUFDIn0=
28
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRhY21lLnBsdWdpbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydGFjbWUucGx1Z2lucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSx1QkFBdUI7QUFDdkIsT0FBTyxLQUFLLFVBQVUsTUFBTSwyQkFBMkIsQ0FBQztBQUV4RCxPQUFPLEVBQUUsVUFBVSxFQUFFLENBQUM7QUFFdEIsbUJBQW1CO0FBQ25CLE9BQU8sS0FBSyxXQUFXLE1BQU0seUJBQXlCLENBQUM7QUFFdkQsT0FBTyxFQUFFLFdBQVcsRUFBRSxDQUFDO0FBRXZCLG1CQUFtQjtBQUNuQixPQUFPLEtBQUssR0FBRyxNQUFNLGlCQUFpQixDQUFDO0FBQ3ZDLE9BQU8sS0FBSyxTQUFTLE1BQU0sdUJBQXVCLENBQUM7QUFDbkQsT0FBTyxLQUFLLFVBQVUsTUFBTSx3QkFBd0IsQ0FBQztBQUNyRCxPQUFPLEtBQUssY0FBYyxNQUFNLDZCQUE2QixDQUFDO0FBQzlELE9BQU8sS0FBSyxRQUFRLE1BQU0sc0JBQXNCLENBQUM7QUFDakQsT0FBTyxLQUFLLFlBQVksTUFBTSwwQkFBMEIsQ0FBQztBQUN6RCxPQUFPLEtBQUssWUFBWSxNQUFNLDBCQUEwQixDQUFDO0FBQ3pELE9BQU8sS0FBSyxXQUFXLE1BQU0seUJBQXlCLENBQUM7QUFDdkQsT0FBTyxLQUFLLFdBQVcsTUFBTSx5QkFBeUIsQ0FBQztBQUN2RCxPQUFPLEtBQUssU0FBUyxNQUFNLHVCQUF1QixDQUFDO0FBRW5ELE9BQU8sRUFDTCxHQUFHLEVBQ0gsU0FBUyxFQUNULFVBQVUsRUFDVixjQUFjLEVBQ2QsUUFBUSxFQUNSLFlBQVksRUFDWixZQUFZLEVBQ1osV0FBVyxFQUNYLFdBQVcsRUFDWCxTQUFTLEdBQ1YsQ0FBQztBQUVGLGlCQUFpQjtBQUNqQixPQUFPLEtBQUssT0FBTyxNQUFNLGtCQUFrQixDQUFDO0FBRTVDLE9BQU8sRUFBRSxPQUFPLEVBQUUsQ0FBQztBQUVuQixvQkFBb0I7QUFDcEIsT0FBTyxLQUFLLElBQUksTUFBTSxhQUFhLENBQUM7QUFFcEMsT0FBTyxFQUFFLElBQUksRUFBRSxDQUFDO0FBQ2hCLHFDQUFxQztBQUNyQyxPQUFPLEtBQUssUUFBUSxNQUFNLHFCQUFxQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxRQUFRLEVBQUUsQ0FBQyJ9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@push.rocks/smartacme",
3
- "version": "6.1.2",
3
+ "version": "6.2.0",
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",
@@ -35,6 +35,7 @@
35
35
  "homepage": "https://code.foss.global/push.rocks/smartacme#readme",
36
36
  "dependencies": {
37
37
  "@api.global/typedserver": "^3.0.74",
38
+ "@apiclient.xyz/cloudflare": "^6.4.1",
38
39
  "@push.rocks/lik": "^6.2.2",
39
40
  "@push.rocks/smartdata": "^5.15.1",
40
41
  "@push.rocks/smartdelay": "^3.0.5",
@@ -45,17 +46,16 @@
45
46
  "@push.rocks/smartstring": "^4.0.15",
46
47
  "@push.rocks/smarttime": "^4.1.1",
47
48
  "@push.rocks/smartunique": "^3.0.9",
48
- "@tsclass/tsclass": "^9.0.0",
49
+ "@tsclass/tsclass": "^9.1.0",
49
50
  "acme-client": "^5.4.0"
50
51
  },
51
52
  "devDependencies": {
52
- "@apiclient.xyz/cloudflare": "^6.3.2",
53
53
  "@git.zone/tsbuild": "^2.3.2",
54
54
  "@git.zone/tsrun": "^1.3.3",
55
55
  "@git.zone/tstest": "^1.0.96",
56
56
  "@push.rocks/qenv": "^6.1.0",
57
- "@push.rocks/tapbundle": "^5.6.3",
58
- "@types/node": "^22.15.2"
57
+ "@push.rocks/tapbundle": "^6.0.0",
58
+ "@types/node": "^22.15.3"
59
59
  },
60
60
  "files": [
61
61
  "ts/**/*",
package/readme.md CHANGED
@@ -61,7 +61,7 @@ const smartAcmeInstance = new SmartAcme({
61
61
  retryOptions: {}, // optional retry/backoff settings
62
62
  challengeHandlers: [
63
63
  new Dns01Handler(cfAccount),
64
- // you can add more handlers, e.g. Http01Handler
64
+ // you can add more handlers, e.g. Http01Webroot
65
65
  ],
66
66
  challengePriority: ['dns-01'], // optional ordering of challenge types
67
67
  });
@@ -143,7 +143,7 @@ async function main() {
143
143
 
144
144
  ## Built-in Challenge Handlers
145
145
 
146
- This module includes two out-of-the-box ACME challenge handlers:
146
+ This module includes three out-of-the-box ACME challenge handlers:
147
147
 
148
148
  - **Dns01Handler**
149
149
  - Uses a Cloudflare account (from `@apiclient.xyz/cloudflare`) and Smartdns client to set and remove DNS TXT records, then wait for propagation.
@@ -158,18 +158,31 @@ async function main() {
158
158
  const dnsHandler = new Dns01Handler(cfAccount);
159
159
  ```
160
160
 
161
- - **Http01Handler**
161
+ - **Http01Webroot**
162
162
  - Writes ACME HTTP-01 challenge files under a file-system webroot (`/.well-known/acme-challenge/`), and removes them on cleanup.
163
163
  - Import path:
164
164
  ```typescript
165
- import { Http01Handler } from '@push.rocks/smartacme/ts/handlers/Http01Handler.js';
165
+ import { Http01Webroot } from '@push.rocks/smartacme/ts/handlers/Http01Handler.js';
166
166
  ```
167
167
  - Example:
168
168
  ```typescript
169
- const httpHandler = new Http01Handler({ webroot: '/var/www/html' });
169
+ const httpHandler = new Http01Webroot({ webroot: '/var/www/html' });
170
170
  ```
171
171
 
172
- Both handlers implement the `IChallengeHandler<T>` interface and can be combined in the `challengeHandlers` array.
172
+ - **Http01MemoryHandler**
173
+ - In-memory HTTP-01 challenge handler that stores and serves ACME tokens without disk I/O.
174
+ - Import path:
175
+ ```typescript
176
+ import { Http01MemoryHandler } from '@push.rocks/smartacme/ts/handlers/Http01MemoryHandler.js';
177
+ ```
178
+ - Example (Express integration):
179
+ ```typescript
180
+ import { Http01MemoryHandler } from '@push.rocks/smartacme/ts/handlers/Http01MemoryHandler.js';
181
+ const memoryHandler = new Http01MemoryHandler();
182
+ app.use((req, res, next) => memoryHandler.handleRequest(req, res, next));
183
+ ```
184
+
185
+ All handlers implement the `IChallengeHandler<T>` interface and can be combined in the `challengeHandlers` array.
173
186
 
174
187
  ## Creating Custom Handlers
175
188
 
package/readme.plan.md ADDED
@@ -0,0 +1,44 @@
1
+ # Plan: Diskless HTTP-01 Handler and Renaming Existing Handler
2
+
3
+ This plan outlines steps to rename the existing filesystem-based HTTP-01 handler to `Http01Webroot`
4
+ and introduce a new diskless (in-memory) HTTP-01 handler for integration with arbitrary HTTP servers
5
+ (e.g., Express).
6
+
7
+ ## 1. Rename existing handler to Http01Webroot
8
+ - In `ts/handlers/Http01Handler.ts`:
9
+ - Rename `Http01HandlerOptions` to `Http01WebrootOptions`.
10
+ - Rename class `Http01Handler` to `Http01Webroot`.
11
+ - Remove the legacy alias; rename the handler directly.
12
+ - In `ts/handlers/index.ts`:
13
+ - Export `Http01Webroot` under its new name.
14
+ - Remove any `Http01Handler` export.
15
+ - Update existing tests (e.g., `test.handlers-http01.ts`) to import `Http01Webroot` instead of `Http01Handler`.
16
+
17
+ ## 2. Add new diskless (in-memory) HTTP-01 handler
18
+ - Create `ts/handlers/Http01MemoryHandler.ts`:
19
+ - Implement `IChallengeHandler<{ token: string; keyAuthorization: string; webPath: string }>`, storing challenges in a private `Map<string, string>`.
20
+ - `prepare()`: add token→keyAuthorization mapping.
21
+ - `verify()`: no-op.
22
+ - `cleanup()`: remove mapping.
23
+ - Add `handleRequest(req, res, next?)` method:
24
+ - Parse `/.well-known/acme-challenge/:token` from `req.url`.
25
+ - If token exists, respond with the key authorization and status 200.
26
+ - If missing and `next` provided, call `next()`, otherwise respond 404.
27
+ - Export `Http01MemoryHandler` in `ts/handlers/index.ts`.
28
+
29
+ ## 3. Write tests for Http01MemoryHandler
30
+ - Create `test/test.handlers-http01-memory.ts`:
31
+ - Use `tap` and `expect` to:
32
+ 1. `prepare()` a challenge.
33
+ 2. Invoke `handleRequest()` with a fake `req`/`res` to confirm 200 and correct body.
34
+ 3. `cleanup()` the challenge.
35
+ 4. Confirm `handleRequest()` now yields 404.
36
+
37
+ ## 4. Update documentation
38
+ - Add examples in `readme.md` showing how to use both `Http01Webroot` and the new `Http01MemoryHandler`:
39
+ - Sample code for Express integration using `handleRequest`.
40
+
41
+ ## 5. Build and test
42
+ - Run `pnpm build` and `pnpm test`, ensuring existing tests are updated for `Http01Webroot` and new tests pass.
43
+
44
+ Please review and let me know if this plan makes sense before proceeding with implementation.
@@ -3,6 +3,6 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@push.rocks/smartacme',
6
- version: '6.1.2',
6
+ version: '6.2.0',
7
7
  description: 'A TypeScript-based ACME client for LetsEncrypt certificate management with a focus on simplicity and power.'
8
8
  }
@@ -5,14 +5,14 @@ import type { IChallengeHandler } from './IChallengeHandler.js';
5
5
  * DNS-01 challenge handler using CloudflareAccount and Smartdns.
6
6
  */
7
7
  export class Dns01Handler implements IChallengeHandler<plugins.tsclass.network.IDnsChallenge> {
8
- private cf: any;
8
+ private cf: plugins.tsclass.network.IConvenientDnsProvider;
9
9
  private smartdns: plugins.smartdnsClient.Smartdns;
10
10
 
11
11
  constructor(
12
- cloudflareAccount: any,
12
+ convenientDnsProvider: plugins.tsclass.network.IConvenientDnsProvider,
13
13
  smartdnsInstance?: plugins.smartdnsClient.Smartdns,
14
14
  ) {
15
- this.cf = cloudflareAccount;
15
+ this.cf = convenientDnsProvider;
16
16
  this.smartdns = smartdnsInstance ?? new plugins.smartdnsClient.Smartdns({});
17
17
  }
18
18
 
@@ -37,4 +37,8 @@ export class Dns01Handler implements IChallengeHandler<plugins.tsclass.network.I
37
37
  // remove DNS TXT record
38
38
  await this.cf.convenience.acmeRemoveDnsChallenge(ch);
39
39
  }
40
+
41
+ public async checkWetherDomainIsSupported(domainArg: string): Promise<boolean> {
42
+ return this.cf.convenience.isDomainSupported(domainArg);
43
+ }
40
44
  }
@@ -6,14 +6,14 @@ import type { IChallengeHandler } from './IChallengeHandler.js';
6
6
  * HTTP-01 ACME challenge handler using file-system webroot.
7
7
  * Writes and removes the challenge file under <webroot>/.well-known/acme-challenge/.
8
8
  */
9
- export interface Http01HandlerOptions {
9
+ export interface Http01WebrootOptions {
10
10
  /**
11
11
  * Directory that serves HTTP requests for /.well-known/acme-challenge
12
12
  */
13
13
  webroot: string;
14
14
  }
15
15
 
16
- export class Http01Handler implements IChallengeHandler<{
16
+ export class Http01Webroot implements IChallengeHandler<{
17
17
  type: string;
18
18
  token: string;
19
19
  keyAuthorization: string;
@@ -21,7 +21,7 @@ export class Http01Handler implements IChallengeHandler<{
21
21
  }> {
22
22
  private webroot: string;
23
23
 
24
- constructor(options: Http01HandlerOptions) {
24
+ constructor(options: Http01WebrootOptions) {
25
25
  this.webroot = options.webroot;
26
26
  }
27
27
 
@@ -0,0 +1,67 @@
1
+ import type { IChallengeHandler } from './IChallengeHandler.js';
2
+
3
+ /**
4
+ * HTTP-01 ACME challenge handler using in-memory storage.
5
+ * Stores challenge tokens and key authorizations in memory
6
+ * and serves them via handleRequest for arbitrary HTTP servers.
7
+ */
8
+ export interface Http01MemoryHandlerChallenge {
9
+ type: string;
10
+ token: string;
11
+ keyAuthorization: string;
12
+ webPath: string;
13
+ }
14
+
15
+ export class Http01MemoryHandler implements IChallengeHandler<Http01MemoryHandlerChallenge> {
16
+ private store: Map<string, string> = new Map();
17
+
18
+ public getSupportedTypes(): string[] {
19
+ return ['http-01'];
20
+ }
21
+
22
+ public async prepare(ch: Http01MemoryHandlerChallenge): Promise<void> {
23
+ this.store.set(ch.token, ch.keyAuthorization);
24
+ }
25
+
26
+ public async verify(_ch: Http01MemoryHandlerChallenge): Promise<void> {
27
+ // No-op
28
+ return;
29
+ }
30
+
31
+ public async cleanup(ch: Http01MemoryHandlerChallenge): Promise<void> {
32
+ this.store.delete(ch.token);
33
+ }
34
+
35
+ /**
36
+ * HTTP request handler for serving ACME HTTP-01 challenges.
37
+ * @param req HTTP request object (should have url property)
38
+ * @param res HTTP response object
39
+ * @param next Optional next() callback for Express-style fallthrough
40
+ */
41
+ public handleRequest(req: any, res: any, next?: () => void): void {
42
+ const url = req.url || '';
43
+ const prefix = '/.well-known/acme-challenge/';
44
+ if (!url.startsWith(prefix)) {
45
+ if (next) {
46
+ return next();
47
+ }
48
+ res.statusCode = 404;
49
+ return res.end();
50
+ }
51
+ const token = url.slice(prefix.length);
52
+ const keyAuth = this.store.get(token);
53
+ if (keyAuth !== undefined) {
54
+ if (typeof res.status === 'function' && typeof res.send === 'function') {
55
+ return res.status(200).send(keyAuth);
56
+ }
57
+ res.statusCode = 200;
58
+ res.setHeader('content-type', 'text/plain');
59
+ return res.end(keyAuth);
60
+ }
61
+ if (next) {
62
+ return next();
63
+ }
64
+ res.statusCode = 404;
65
+ return res.end();
66
+ }
67
+ }
@@ -1,4 +1,5 @@
1
1
  export type { IChallengeHandler } from './IChallengeHandler.js';
2
2
  // Removed legacy handler adapter
3
3
  export { Dns01Handler } from './Dns01Handler.js';
4
- export { Http01Handler } from './Http01Handler.js';
4
+ export { Http01Webroot } from './Http01Handler.js';
5
+ export { Http01MemoryHandler } from './Http01MemoryHandler.js';
@@ -1,3 +1,8 @@
1
+ // @apiclient.xyz scope
2
+ import * as cloudflare from '@apiclient.xyz/cloudflare';
3
+
4
+ export { cloudflare };
5
+
1
6
  // @apiglobal scope
2
7
  import * as typedserver from '@api.global/typedserver';
3
8