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