All files / packages/core/src https-enabler.ts

0% Statements 0/59
100% Branches 1/1
100% Functions 1/1
0% Lines 0/59

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101                                                                                                                                                                                                         
import type { Certificate } from '@https-enable/mkcert'
import type { Prettify } from '@https-enable/types'
import type { HttpsEnablerEvents } from './emitter'
import type { HttpsAdapter } from './https-adapter'
import type { AppType, CertificateManagerOptions, MiddlewareType, ServerOptions } from './type'
import { EventEmitter } from 'node:events'
import { CertificateManager } from './certificate-manager'
import logger from './logger'
 
export class HttpsEnabler<
  App extends AppType,
  Middleware = MiddlewareType,
> extends EventEmitter<HttpsEnablerEvents> {
  public adapter: HttpsAdapter<App, Middleware>
  protected options: Prettify<ServerOptions &
    {
      /**
       * http 301 重定向至 https
       */
      redirect?: boolean
    }>
 
  protected certificateOptions: CertificateManagerOptions
 
  protected certManager: CertificateManager
 
  constructor(config: {
    adapter: typeof HttpsEnabler.prototype.adapter
    options: typeof HttpsEnabler.prototype.options
    certificateOptions: typeof HttpsEnabler.prototype.certificateOptions
  }) {
    super()
    this.adapter = config.adapter
    if (!this.adapter) {
      throw logger.error('Must provide the adapter')
    }
    if (
      (!this.adapter.app && (!this.adapter.init || typeof this.adapter.init !== 'function'))
      || typeof this.adapter.createServer !== 'function'
    ) {
      throw logger.error('The adapter is invalid')
    }
 
    this.options = config.options
    this.certificateOptions = config.certificateOptions
 
    this.certManager = new CertificateManager(this.certificateOptions)
 
    // 证书更新监听
    this.certManager.on('cert-renewed', async (newCert) => {
      this.emit('cert-renewed', newCert)
      // 通知适配器证书更新(如热重载)
      await this.adapter.serverInstance?.refresh(newCert)
      this.adapter.onCertRenewed?.(newCert)
    })
  }
 
  public async init() {
    // 初始化证书
    await this.certManager.initialize().catch(err => this.emit('error', err))
  }
 
  /**
   * 生成框架特定的中间件
   */
  public middleware() {
    return this.adapter.createMiddleware?.(this.options)
  }
 
  public refresh(options: Certificate) {
    if (!this.adapter.serverInstance)
      return
 
    return this.adapter.serverInstance.refresh(options)
  }
 
  public kill() {
    if (!this.adapter.serverInstance)
      return
 
    return this.adapter.serverInstance.kill()
  }
 
  /**
   * 启动 HTTPS 服务
   */
  public async startServer(app?: App) {
    // 确保证书已就绪
    await this.certManager.ensureValidCert()
    // 如果适配器有自定义服务启动逻辑,优先使用
    if (typeof this.adapter.createServer === 'function' && this.certManager.currentCert) {
      const options = { ...this.options, ...this.certManager.currentCert }
      await this.adapter.createServer(options, app)
      return options
    }
    else {
      throw new TypeError('Unsupported framework: default server logic requires an app with listen()')
    }
  }
}