SignerType.ts raw

   1  /**
   2   * SignerType Value Object
   3   *
   4   * Represents the type of signer/authentication method used for an account.
   5   */
   6  
   7  const VALID_SIGNER_TYPES = ['nsec', 'nip-07', 'browser-nsec', 'ncryptsec', 'npub', 'bunker'] as const
   8  
   9  export type SignerTypeValue = (typeof VALID_SIGNER_TYPES)[number]
  10  
  11  /**
  12   * SignerType Value Object
  13   *
  14   * Represents how a user authenticates and signs events.
  15   * - nsec: Raw private key (stored securely)
  16   * - nip-07: Browser extension (nos2x, Alby, etc.)
  17   * - browser-nsec: Private key in browser storage (less secure)
  18   * - ncryptsec: Encrypted private key (NIP-49)
  19   * - npub: View-only mode (no signing capability)
  20   */
  21  export class SignerType {
  22    private constructor(private readonly _value: SignerTypeValue) {}
  23  
  24    static readonly NSEC = new SignerType('nsec')
  25    static readonly NIP07 = new SignerType('nip-07')
  26    static readonly BROWSER_NSEC = new SignerType('browser-nsec')
  27    static readonly NCRYPTSEC = new SignerType('ncryptsec')
  28    static readonly NPUB = new SignerType('npub')
  29    static readonly BUNKER = new SignerType('bunker')
  30  
  31    /**
  32     * Create a SignerType from a string value
  33     */
  34    static fromString(value: string): SignerType {
  35      if (!SignerType.isValid(value)) {
  36        throw new Error(`Invalid signer type: ${value}`)
  37      }
  38      return new SignerType(value as SignerTypeValue)
  39    }
  40  
  41    /**
  42     * Try to create a SignerType from a string, returns null if invalid
  43     */
  44    static tryFromString(value: string): SignerType | null {
  45      try {
  46        return SignerType.fromString(value)
  47      } catch {
  48        return null
  49      }
  50    }
  51  
  52    /**
  53     * Check if a string is a valid signer type
  54     */
  55    static isValid(value: string): value is SignerTypeValue {
  56      return VALID_SIGNER_TYPES.includes(value as SignerTypeValue)
  57    }
  58  
  59    /**
  60     * Get all valid signer types
  61     */
  62    static all(): SignerType[] {
  63      return VALID_SIGNER_TYPES.map((v) => new SignerType(v))
  64    }
  65  
  66    /**
  67     * The raw string value
  68     */
  69    get value(): SignerTypeValue {
  70      return this._value
  71    }
  72  
  73    /**
  74     * Whether this signer can sign events
  75     */
  76    get canSign(): boolean {
  77      return this._value !== 'npub'
  78    }
  79  
  80    /**
  81     * Whether this signer stores keys locally
  82     */
  83    get storesKeysLocally(): boolean {
  84      return ['nsec', 'browser-nsec', 'ncryptsec'].includes(this._value)
  85    }
  86  
  87    /**
  88     * Whether this signer uses a remote/external service
  89     */
  90    get isRemote(): boolean {
  91      return this._value === 'nip-07' || this._value === 'bunker'
  92    }
  93  
  94    /**
  95     * Whether this is view-only mode
  96     */
  97    get isViewOnly(): boolean {
  98      return this._value === 'npub'
  99    }
 100  
 101    /**
 102     * Human-readable display name
 103     */
 104    get displayName(): string {
 105      switch (this._value) {
 106        case 'nsec':
 107          return 'Private Key'
 108        case 'nip-07':
 109          return 'Browser Extension'
 110        case 'browser-nsec':
 111          return 'Browser Key'
 112        case 'ncryptsec':
 113          return 'Encrypted Key'
 114        case 'npub':
 115          return 'View Only'
 116        case 'bunker':
 117          return 'Remote Signer'
 118      }
 119    }
 120  
 121    /**
 122     * Check equality with another SignerType
 123     */
 124    equals(other: SignerType): boolean {
 125      return this._value === other._value
 126    }
 127  
 128    /**
 129     * Returns the string value
 130     */
 131    toString(): string {
 132      return this._value
 133    }
 134  
 135    /**
 136     * For JSON serialization
 137     */
 138    toJSON(): string {
 139      return this._value
 140    }
 141  }
 142