applesauce-accounts 0.0.0-next-20250124172415 → 0.0.0-next-20250124224517

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.
package/README.md CHANGED
@@ -1,3 +1,5 @@
1
1
  # applesauce-accounts
2
2
 
3
- A simple nostr account management system
3
+ A simple nostr account management system built on top of [applesauce-signer](https://hzrd149.github.io/applesauce/signers/installation.html)
4
+
5
+ See [documentation](https://hzrd149.github.io/applesauce/signers/signers.html)
package/dist/account.d.ts CHANGED
@@ -1,15 +1,14 @@
1
1
  import { Nip07Interface } from "applesauce-signer";
2
- import { EventTemplate } from "nostr-tools";
3
- import { IAccount, SerializedAccount } from "./types.js";
2
+ import { EventTemplate, IAccount, SerializedAccount } from "./types.js";
4
3
  export declare class SignerMismatchError extends Error {
5
4
  }
6
5
  export declare class AccountLockedError extends Error {
7
6
  }
8
- export declare class BaseAccount<T extends string, S> implements IAccount<T, S> {
7
+ export declare class BaseAccount<Signer extends Nip07Interface, SignerData, Metadata extends unknown> implements IAccount<Signer, SignerData, Metadata> {
9
8
  pubkey: string;
10
- signer: Nip07Interface;
11
- name?: string;
12
- locked: boolean;
9
+ signer: Signer;
10
+ id: string;
11
+ metadata?: Metadata;
13
12
  nip04?: {
14
13
  encrypt: (pubkey: string, plaintext: string) => Promise<string> | string;
15
14
  decrypt: (pubkey: string, ciphertext: string) => Promise<string> | string;
@@ -18,12 +17,8 @@ export declare class BaseAccount<T extends string, S> implements IAccount<T, S>
18
17
  encrypt: (pubkey: string, plaintext: string) => Promise<string> | string;
19
18
  decrypt: (pubkey: string, ciphertext: string) => Promise<string> | string;
20
19
  } | undefined;
21
- constructor(pubkey: string, signer: Nip07Interface);
22
- unlock(): Promise<boolean>;
23
- lock(): void;
24
- toJSON(): SerializedAccount<T, S>;
25
- /** throws if account is locked */
26
- protected checkLocked(): void;
20
+ constructor(pubkey: string, signer: Signer);
21
+ toJSON(): SerializedAccount<SignerData, Metadata>;
27
22
  /** Gets the pubkey from the signer */
28
23
  getPublicKey(): Promise<string>;
29
24
  /** sign the event and make sure its signed with the correct pubkey */
package/dist/account.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { nanoid } from "nanoid";
1
2
  // errors
2
3
  export class SignerMismatchError extends Error {
3
4
  }
@@ -6,8 +7,8 @@ export class AccountLockedError extends Error {
6
7
  export class BaseAccount {
7
8
  pubkey;
8
9
  signer;
9
- name;
10
- locked = true;
10
+ id = nanoid(8);
11
+ metadata;
11
12
  // encryption interfaces
12
13
  nip04;
13
14
  nip44;
@@ -18,11 +19,9 @@ export class BaseAccount {
18
19
  if (this.signer.nip04) {
19
20
  this.nip04 = {
20
21
  encrypt: (pubkey, plaintext) => {
21
- this.checkLocked();
22
22
  return this.signer.nip04.encrypt(pubkey, plaintext);
23
23
  },
24
24
  decrypt: (pubkey, plaintext) => {
25
- this.checkLocked();
26
25
  return this.signer.nip04.decrypt(pubkey, plaintext);
27
26
  },
28
27
  };
@@ -30,35 +29,21 @@ export class BaseAccount {
30
29
  if (this.signer.nip44) {
31
30
  this.nip44 = {
32
31
  encrypt: (pubkey, plaintext) => {
33
- this.checkLocked();
34
32
  return this.signer.nip44.encrypt(pubkey, plaintext);
35
33
  },
36
34
  decrypt: (pubkey, plaintext) => {
37
- this.checkLocked();
38
35
  return this.signer.nip44.decrypt(pubkey, plaintext);
39
36
  },
40
37
  };
41
38
  }
42
39
  }
43
- async unlock() {
44
- this.locked = false;
45
- return true;
46
- }
47
- lock() {
48
- this.locked = true;
49
- }
50
40
  // This should be overwritten by a sub class
51
41
  toJSON() {
52
42
  throw new Error("Not implemented");
53
43
  }
54
- /** throws if account is locked */
55
- checkLocked() {
56
- if (this.locked)
57
- throw new AccountLockedError("Account is locked");
58
- }
59
44
  /** Gets the pubkey from the signer */
60
45
  async getPublicKey() {
61
- this.checkLocked();
46
+ // this.checkLocked();
62
47
  const signerKey = await this.signer.getPublicKey();
63
48
  if (this.pubkey !== signerKey)
64
49
  throw new Error("Account signer mismatch");
@@ -66,7 +51,7 @@ export class BaseAccount {
66
51
  }
67
52
  /** sign the event and make sure its signed with the correct pubkey */
68
53
  async signEvent(template) {
69
- this.checkLocked();
54
+ // this.checkLocked();
70
55
  if (!Reflect.has(template, "pubkey"))
71
56
  Reflect.set(template, "pubkey", this.pubkey);
72
57
  const signed = await this.signer.signEvent(template);
@@ -1,10 +1,9 @@
1
1
  import { AmberClipboardSigner } from "applesauce-signer/signers/amber-clipboard-signer";
2
2
  import { BaseAccount } from "../account.js";
3
- import { IAccount, SerializedAccount } from "../types.js";
3
+ import { SerializedAccount } from "../types.js";
4
4
  /** An account for the amber clipboard api */
5
- export declare class AmberClipboardAccount extends BaseAccount<"amber-clipboard", void> {
6
- signer: AmberClipboardSigner;
7
- constructor(pubkey: string, signer: AmberClipboardSigner);
8
- toJSON(): SerializedAccount<"amber-clipboard", void>;
9
- static fromJSON(json: SerializedAccount<"amber-clipboard", void>): IAccount<"amber-clipboard", void>;
5
+ export declare class AmberClipboardAccount<Metadata extends unknown> extends BaseAccount<AmberClipboardSigner, void, Metadata> {
6
+ static type: string;
7
+ toJSON(): SerializedAccount<void, Metadata>;
8
+ static fromJSON<MD extends unknown>(json: SerializedAccount<void, MD>): AmberClipboardAccount<MD>;
10
9
  }
@@ -2,13 +2,15 @@ import { AmberClipboardSigner } from "applesauce-signer/signers/amber-clipboard-
2
2
  import { BaseAccount } from "../account.js";
3
3
  /** An account for the amber clipboard api */
4
4
  export class AmberClipboardAccount extends BaseAccount {
5
- signer;
6
- constructor(pubkey, signer) {
7
- super(pubkey, signer);
8
- this.signer = signer;
9
- }
5
+ static type = "amber-clipboard";
10
6
  toJSON() {
11
- return { type: "amber-clipboard", pubkey: this.pubkey, name: this.name, signer: void 0 };
7
+ return {
8
+ type: AmberClipboardAccount.type,
9
+ id: this.id,
10
+ pubkey: this.pubkey,
11
+ metadata: this.metadata,
12
+ signer: undefined,
13
+ };
12
14
  }
13
15
  static fromJSON(json) {
14
16
  return new AmberClipboardAccount(json.pubkey, new AmberClipboardSigner());
@@ -0,0 +1,3 @@
1
+ import { AccountManager } from "../manager.js";
2
+ /** Registers the most common account types to a account manager */
3
+ export declare function registerCommonAccountTypes(manager: AccountManager): void;
@@ -0,0 +1,11 @@
1
+ import ExtensionAccount from "./extension-account.js";
2
+ import PasswordAccount from "./password-account.js";
3
+ import ReadonlyAccount from "./readonly-account.js";
4
+ import SimpleAccount from "./simple-account.js";
5
+ /** Registers the most common account types to a account manager */
6
+ export function registerCommonAccountTypes(manager) {
7
+ manager.registerType(ExtensionAccount);
8
+ manager.registerType(PasswordAccount);
9
+ manager.registerType(ReadonlyAccount);
10
+ manager.registerType(SimpleAccount);
11
+ }
@@ -1,7 +1,16 @@
1
+ import { ExtensionSigner } from "applesauce-signer/signers/extension-signer";
1
2
  import { BaseAccount } from "../account.js";
2
3
  import { SerializedAccount } from "../types.js";
3
- export default class ExtensionAccount extends BaseAccount<"extension", void> {
4
- constructor(pubkey: string);
5
- toJSON(): SerializedAccount<"extension", void>;
6
- static fromJSON(json: SerializedAccount<"extension", void>): ExtensionAccount;
4
+ export default class ExtensionAccount<Metadata extends unknown> extends BaseAccount<ExtensionSigner, void, Metadata> {
5
+ signer: ExtensionSigner;
6
+ static type: string;
7
+ constructor(pubkey: string, signer: ExtensionSigner);
8
+ toJSON(): {
9
+ type: string;
10
+ id: string;
11
+ pubkey: string;
12
+ metadata: Metadata | undefined;
13
+ signer: undefined;
14
+ };
15
+ static fromJSON<MD extends unknown>(json: SerializedAccount<void, MD>): ExtensionAccount<unknown>;
7
16
  }
@@ -1,13 +1,22 @@
1
1
  import { ExtensionSigner } from "applesauce-signer/signers/extension-signer";
2
2
  import { BaseAccount } from "../account.js";
3
3
  export default class ExtensionAccount extends BaseAccount {
4
- constructor(pubkey) {
5
- super(pubkey, new ExtensionSigner());
4
+ signer;
5
+ static type = "extension";
6
+ constructor(pubkey, signer) {
7
+ super(pubkey, signer || new ExtensionSigner());
8
+ this.signer = signer;
6
9
  }
7
10
  toJSON() {
8
- return { type: "extension", pubkey: this.pubkey, signer: undefined };
11
+ return {
12
+ type: ExtensionAccount.type,
13
+ id: this.id,
14
+ pubkey: this.pubkey,
15
+ metadata: this.metadata,
16
+ signer: undefined,
17
+ };
9
18
  }
10
19
  static fromJSON(json) {
11
- return new ExtensionAccount(json.pubkey);
20
+ return new ExtensionAccount(json.pubkey, new ExtensionSigner());
12
21
  }
13
22
  }
@@ -4,3 +4,5 @@ export * from "./password-account.js";
4
4
  export * from "./readonly-account.js";
5
5
  export * from "./serial-port-account.js";
6
6
  export * from "./simple-account.js";
7
+ export * from "./nostr-connect-account.js";
8
+ export * from "./common.js";
@@ -4,3 +4,5 @@ export * from "./password-account.js";
4
4
  export * from "./readonly-account.js";
5
5
  export * from "./serial-port-account.js";
6
6
  export * from "./simple-account.js";
7
+ export * from "./nostr-connect-account.js";
8
+ export * from "./common.js";
@@ -0,0 +1,17 @@
1
+ import { NostrConnectConnectionMethods, NostrConnectSigner } from "applesauce-signer";
2
+ import { BaseAccount } from "../account.js";
3
+ import { SerializedAccount } from "../types.js";
4
+ type SignerData = {
5
+ clientKey: string;
6
+ remote: string;
7
+ relays: string[];
8
+ };
9
+ /** An account type for NIP-46 signers */
10
+ export declare class NostrConnectAccount<Metadata extends unknown> extends BaseAccount<NostrConnectSigner, SignerData, Metadata> {
11
+ static type: string;
12
+ toJSON(): SerializedAccount<SignerData, Metadata>;
13
+ /** This is called when NostrConnectAccount.fromJSON needs new connection methods for NostrConnectSigner */
14
+ static createConnectionMethods(): NostrConnectConnectionMethods;
15
+ static fromJSON<Metadata extends unknown>(json: SerializedAccount<SignerData, Metadata>, connection?: NostrConnectConnectionMethods): NostrConnectAccount<Metadata>;
16
+ }
17
+ export {};
@@ -0,0 +1,32 @@
1
+ import { NostrConnectSigner, SimpleSigner } from "applesauce-signer";
2
+ import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
3
+ import { BaseAccount } from "../account.js";
4
+ /** An account type for NIP-46 signers */
5
+ export class NostrConnectAccount extends BaseAccount {
6
+ static type = "nostr-connect";
7
+ toJSON() {
8
+ if (!this.signer.remote)
9
+ throw new Error("Cant save NostrConnectAccount when not initialized");
10
+ const signer = {
11
+ clientKey: bytesToHex(this.signer.signer.key),
12
+ remote: this.signer.remote,
13
+ relays: this.signer.relays,
14
+ };
15
+ return { type: NostrConnectAccount.type, id: this.id, pubkey: this.pubkey, metadata: this.metadata, signer };
16
+ }
17
+ /** This is called when NostrConnectAccount.fromJSON needs new connection methods for NostrConnectSigner */
18
+ static createConnectionMethods() {
19
+ throw new Error("Cant create NostrConnectAccount without either passing in connection methods or setting NostrConnectAccount.createConnectionMethods");
20
+ }
21
+ static fromJSON(json, connection) {
22
+ connection = connection || NostrConnectAccount.createConnectionMethods();
23
+ const signer = new NostrConnectSigner({
24
+ ...connection,
25
+ relays: json.signer.relays,
26
+ pubkey: json.pubkey,
27
+ remote: json.signer.remote,
28
+ signer: new SimpleSigner(hexToBytes(json.signer.clientKey)),
29
+ });
30
+ return new NostrConnectAccount(json.pubkey, signer);
31
+ }
32
+ }
@@ -4,12 +4,19 @@ import { SerializedAccount } from "../types.js";
4
4
  type SignerData = {
5
5
  ncryptsec: string;
6
6
  };
7
- export default class PasswordAccount extends BaseAccount<"ncryptsec", SignerData> {
8
- signer: PasswordSigner;
9
- constructor(pubkey: string, signer: PasswordSigner);
10
- unlock(): Promise<boolean>;
11
- toJSON(): SerializedAccount<"ncryptsec", SignerData>;
12
- static fromJSON(json: SerializedAccount<"ncryptsec", SignerData>): PasswordAccount;
13
- static fromNcryptsec(pubkey: string, ncryptsec: string): PasswordAccount;
7
+ export default class PasswordAccount<Metadata extends unknown> extends BaseAccount<PasswordSigner, SignerData, Metadata> {
8
+ static type: string;
9
+ get unlocked(): boolean;
10
+ /** called when PasswordAccount.unlock is called without a password */
11
+ static requestUnlockPassword(_account: PasswordAccount<any>): Promise<string>;
12
+ /**
13
+ * Attempt to unlock the signer with a password
14
+ * @throws
15
+ */
16
+ unlock(password?: string): Promise<void>;
17
+ toJSON(): SerializedAccount<SignerData, Metadata>;
18
+ static fromJSON<Metadata extends unknown>(json: SerializedAccount<SignerData, Metadata>): PasswordAccount<Metadata>;
19
+ /** Creates a new PasswordAccount from a ncryptsec string */
20
+ static fromNcryptsec<Metadata extends unknown>(pubkey: string, ncryptsec: string): PasswordAccount<Metadata>;
14
21
  }
15
22
  export {};
@@ -1,33 +1,39 @@
1
1
  import { PasswordSigner } from "applesauce-signer/signers/password-signer";
2
2
  import { BaseAccount } from "../account.js";
3
3
  export default class PasswordAccount extends BaseAccount {
4
- signer;
5
- constructor(pubkey, signer) {
6
- super(pubkey, signer);
7
- this.signer = signer;
4
+ static type = "ncryptsec";
5
+ get unlocked() {
6
+ return this.signer.unlocked;
8
7
  }
9
- async unlock() {
10
- try {
11
- const password = prompt("Unlock password");
12
- if (password === null)
13
- return false;
14
- await this.signer.unlock(password);
15
- return true;
16
- }
17
- catch (error) {
18
- return false;
19
- }
8
+ /** called when PasswordAccount.unlock is called without a password */
9
+ static async requestUnlockPassword(_account) {
10
+ throw new Error("Cant unlock PasswordAccount without a password. either pass one in or set PasswordAccount.requestUnlockPassword");
11
+ }
12
+ /**
13
+ * Attempt to unlock the signer with a password
14
+ * @throws
15
+ */
16
+ async unlock(password) {
17
+ password = password || (await PasswordAccount.requestUnlockPassword(this));
18
+ await this.signer.unlock(password);
20
19
  }
21
20
  toJSON() {
22
21
  if (!this.signer.ncryptsec)
23
22
  throw new Error("Cant save account without ncryptsec");
24
- return { type: "ncryptsec", pubkey: this.pubkey, signer: { ncryptsec: this.signer.ncryptsec } };
23
+ return {
24
+ type: PasswordAccount.type,
25
+ id: this.id,
26
+ pubkey: this.pubkey,
27
+ metadata: this.metadata,
28
+ signer: { ncryptsec: this.signer.ncryptsec },
29
+ };
25
30
  }
26
31
  static fromJSON(json) {
27
32
  const signer = new PasswordSigner();
28
33
  signer.ncryptsec = json.signer.ncryptsec;
29
34
  return new PasswordAccount(json.pubkey, signer);
30
35
  }
36
+ /** Creates a new PasswordAccount from a ncryptsec string */
31
37
  static fromNcryptsec(pubkey, ncryptsec) {
32
38
  const signer = new PasswordSigner();
33
39
  signer.ncryptsec = ncryptsec;
@@ -2,8 +2,14 @@ import { ReadonlySigner } from "applesauce-signer/signers/readonly-signer";
2
2
  import { BaseAccount } from "../account.js";
3
3
  import { SerializedAccount } from "../types.js";
4
4
  /** An account that cannot sign or encrypt anything */
5
- export default class ReadonlyAccount extends BaseAccount<"readonly", void> {
6
- constructor(pubkey: string, signer?: ReadonlySigner);
7
- toJSON(): SerializedAccount<"readonly", void>;
8
- static fromJSON(json: SerializedAccount<"readonly", void>): ReadonlyAccount;
5
+ export default class ReadonlyAccount<Metadata extends unknown> extends BaseAccount<ReadonlySigner, void, Metadata> {
6
+ static type: string;
7
+ toJSON(): {
8
+ type: string;
9
+ id: string;
10
+ pubkey: string;
11
+ metadata: Metadata | undefined;
12
+ signer: undefined;
13
+ };
14
+ static fromJSON<Metadata extends unknown>(json: SerializedAccount<void, Metadata>): ReadonlyAccount<Metadata>;
9
15
  }
@@ -2,17 +2,17 @@ import { ReadonlySigner } from "applesauce-signer/signers/readonly-signer";
2
2
  import { BaseAccount } from "../account.js";
3
3
  /** An account that cannot sign or encrypt anything */
4
4
  export default class ReadonlyAccount extends BaseAccount {
5
- constructor(pubkey, signer) {
6
- super(pubkey, signer || new ReadonlySigner(pubkey));
7
- }
5
+ static type = "readonly";
8
6
  toJSON() {
9
7
  return {
10
- type: "readonly",
8
+ type: ReadonlyAccount.type,
9
+ id: this.id,
11
10
  pubkey: this.pubkey,
11
+ metadata: this.metadata,
12
12
  signer: undefined,
13
13
  };
14
14
  }
15
15
  static fromJSON(json) {
16
- return new ReadonlyAccount(json.pubkey);
16
+ return new ReadonlyAccount(json.pubkey, new ReadonlySigner(json.pubkey));
17
17
  }
18
18
  }
@@ -2,9 +2,9 @@ import { SerialPortSigner } from "applesauce-signer/signers/serial-port-signer";
2
2
  import { BaseAccount } from "../account.js";
3
3
  import { SerializedAccount } from "../types.js";
4
4
  /** An account for SerialPortSigner */
5
- export default class SerialPortAccount extends BaseAccount<"serial-port", void> {
6
- constructor(pubkey: string, signer?: SerialPortSigner);
5
+ export default class SerialPortAccount<Metadata extends unknown> extends BaseAccount<SerialPortSigner, void, Metadata> {
6
+ static type: string;
7
7
  unlock(): Promise<boolean>;
8
- toJSON(): SerializedAccount<"serial-port", void>;
9
- static fromJSON(json: SerializedAccount<"serial-port", void>): SerialPortAccount;
8
+ toJSON(): SerializedAccount<void, Metadata>;
9
+ static fromJSON<Metadata extends unknown>(json: SerializedAccount<void, Metadata>): SerialPortAccount<Metadata>;
10
10
  }
@@ -2,9 +2,7 @@ import { SerialPortSigner } from "applesauce-signer/signers/serial-port-signer";
2
2
  import { BaseAccount } from "../account.js";
3
3
  /** An account for SerialPortSigner */
4
4
  export default class SerialPortAccount extends BaseAccount {
5
- constructor(pubkey, signer) {
6
- super(pubkey, signer || new SerialPortSigner());
7
- }
5
+ static type = "serial-port";
8
6
  async unlock() {
9
7
  try {
10
8
  const pubkey = await this.signer.getPublicKey();
@@ -17,9 +15,15 @@ export default class SerialPortAccount extends BaseAccount {
17
15
  }
18
16
  }
19
17
  toJSON() {
20
- return { type: "serial-port", pubkey: this.pubkey, signer: undefined };
18
+ return {
19
+ type: SerialPortAccount.type,
20
+ id: this.id,
21
+ pubkey: this.pubkey,
22
+ metadata: this.metadata,
23
+ signer: undefined,
24
+ };
21
25
  }
22
26
  static fromJSON(json) {
23
- return new SerialPortAccount(json.pubkey);
27
+ return new SerialPortAccount(json.pubkey, new SerialPortSigner());
24
28
  }
25
29
  }
@@ -4,11 +4,10 @@ import { SerializedAccount } from "../types.js";
4
4
  type SignerData = {
5
5
  key: string;
6
6
  };
7
- export default class SimpleAccount extends BaseAccount<"nsec", SignerData> {
8
- signer: SimpleSigner;
9
- constructor(pubkey: string, signer: SimpleSigner);
10
- static fromKey(key: Uint8Array | string): SimpleAccount;
11
- toJSON(): SerializedAccount<"nsec", SignerData>;
12
- static fromJSON(json: SerializedAccount<"nsec", SignerData>): SimpleAccount;
7
+ export default class SimpleAccount<Metadata extends unknown> extends BaseAccount<SimpleSigner, SignerData, Metadata> {
8
+ static type: string;
9
+ toJSON(): SerializedAccount<SignerData, Metadata>;
10
+ static fromJSON<Metadata extends unknown>(json: SerializedAccount<SignerData, Metadata>): SimpleAccount<Metadata>;
11
+ static fromKey<Metadata extends unknown>(key: Uint8Array | string): SimpleAccount<Metadata>;
13
12
  }
14
13
  export {};
@@ -3,10 +3,19 @@ import { SimpleSigner } from "applesauce-signer/signers/simple-signer";
3
3
  import { bytesToHex, hexToBytes } from "@noble/hashes/utils";
4
4
  import { BaseAccount } from "../account.js";
5
5
  export default class SimpleAccount extends BaseAccount {
6
- signer;
7
- constructor(pubkey, signer) {
8
- super(pubkey, signer);
9
- this.signer = signer;
6
+ static type = "nsec";
7
+ toJSON() {
8
+ return {
9
+ type: SimpleAccount.type,
10
+ id: this.id,
11
+ pubkey: this.pubkey,
12
+ metadata: this.metadata,
13
+ signer: { key: bytesToHex(this.signer.key) },
14
+ };
15
+ }
16
+ static fromJSON(json) {
17
+ const key = hexToBytes(json.signer.key);
18
+ return new SimpleAccount(json.pubkey, new SimpleSigner(key));
10
19
  }
11
20
  static fromKey(key) {
12
21
  if (typeof key === "string")
@@ -14,11 +23,4 @@ export default class SimpleAccount extends BaseAccount {
14
23
  const pubkey = getPublicKey(key);
15
24
  return new SimpleAccount(pubkey, new SimpleSigner(key));
16
25
  }
17
- toJSON() {
18
- return { type: "nsec", pubkey: this.pubkey, signer: { key: bytesToHex(this.signer.key) } };
19
- }
20
- static fromJSON(json) {
21
- const key = hexToBytes(json.signer.key);
22
- return new SimpleAccount(json.pubkey, new SimpleSigner(key));
23
- }
24
26
  }
package/dist/manager.d.ts CHANGED
@@ -1,2 +1,37 @@
1
- export declare class AccountManager {
1
+ import { Nip07Interface } from "applesauce-signer";
2
+ import { BehaviorSubject } from "rxjs";
3
+ import { IAccount, IAccountConstructor, SerializedAccount } from "./types.js";
4
+ export declare class AccountManager<Metadata extends unknown = any> {
5
+ active: BehaviorSubject<IAccount<any, any, Metadata> | null>;
6
+ accounts: BehaviorSubject<Record<string, IAccount<any, any, Metadata>>>;
7
+ types: Map<string, IAccountConstructor<any, any, Metadata>>;
8
+ /** Add account type class */
9
+ registerType<S extends Nip07Interface>(accountType: IAccountConstructor<S, any, Metadata>): void;
10
+ /** Remove account type */
11
+ unregisterType(type: string): void;
12
+ /** gets an account in the manager */
13
+ getAccount<S extends Nip07Interface>(id: string | IAccount<S, any, Metadata>): IAccount<S, any, Metadata> | undefined;
14
+ /** adds an account to the manager */
15
+ addAccount(account: IAccount<any, any, Metadata>): void;
16
+ /** Removes an account from the manager */
17
+ removeAccount(account: string | IAccount<any, any, Metadata>): void;
18
+ /** Replaces an account with another */
19
+ replaceAccount(old: string | IAccount<any, any, Metadata>, account: IAccount<any, any, Metadata>): void;
20
+ /** Returns the currently active account */
21
+ getActive(): IAccount<any, any, Metadata> | null;
22
+ /** Sets the currently active account */
23
+ setActive(id: string | IAccount<any, any, Metadata>): void;
24
+ /** Clears the currently active account */
25
+ clearActive(): void;
26
+ /** sets the metadata on an account */
27
+ setAccountMetadata(id: string | IAccount<any, any, Metadata>, metadata: Metadata): void;
28
+ /** Removes all metadata on the account */
29
+ clearAccountMetadata(id: string | IAccount<any, any, Metadata>): void;
30
+ /** Returns an array of serialized accounts */
31
+ toJSON(): SerializedAccount<any, Metadata>[];
32
+ /**
33
+ * Restores all accounts from an array of serialized accounts
34
+ * NOTE: this will clear all existing accounts
35
+ */
36
+ fromJSON(accounts: SerializedAccount<any, Metadata>[], quite?: boolean): void;
2
37
  }
package/dist/manager.js CHANGED
@@ -1,2 +1,115 @@
1
+ import { BehaviorSubject } from "rxjs";
1
2
  export class AccountManager {
3
+ active = new BehaviorSubject(null);
4
+ accounts = new BehaviorSubject({});
5
+ types = new Map();
6
+ // Account type CRUD
7
+ /** Add account type class */
8
+ registerType(accountType) {
9
+ if (!accountType.type)
10
+ throw new Error(`Account class missing static "type" field`);
11
+ if (this.types.has(accountType.type))
12
+ throw new Error(`An account type of ${accountType.type} already exists`);
13
+ this.types.set(accountType.type, accountType);
14
+ }
15
+ /** Remove account type */
16
+ unregisterType(type) {
17
+ this.types.delete(type);
18
+ }
19
+ // Accounts CRUD
20
+ /** gets an account in the manager */
21
+ getAccount(id) {
22
+ if (typeof id === "string")
23
+ return this.accounts.value[id];
24
+ else if (this.accounts.value[id.id])
25
+ return id;
26
+ else
27
+ return undefined;
28
+ }
29
+ /** adds an account to the manager */
30
+ addAccount(account) {
31
+ if (this.getAccount(account.id))
32
+ return;
33
+ this.accounts.next({
34
+ ...this.accounts.value,
35
+ [account.id]: account,
36
+ });
37
+ }
38
+ /** Removes an account from the manager */
39
+ removeAccount(account) {
40
+ const id = typeof account === "string" ? account : account.id;
41
+ const next = { ...this.accounts.value };
42
+ delete next[id];
43
+ this.accounts.next(next);
44
+ }
45
+ /** Replaces an account with another */
46
+ replaceAccount(old, account) {
47
+ this.addAccount(account);
48
+ // if the old account was active, switch to the new one
49
+ const id = typeof account === "string" ? account : account.id;
50
+ if (this.active.value?.id === id)
51
+ this.setActive(account);
52
+ this.removeAccount(old);
53
+ }
54
+ // Active account methods
55
+ /** Returns the currently active account */
56
+ getActive() {
57
+ return this.active.value;
58
+ }
59
+ /** Sets the currently active account */
60
+ setActive(id) {
61
+ const account = this.getAccount(id);
62
+ if (!account)
63
+ throw new Error("Cant find account with that ID");
64
+ if (this.active.value?.id !== account.id) {
65
+ this.active.next(account);
66
+ }
67
+ }
68
+ /** Clears the currently active account */
69
+ clearActive() {
70
+ this.active.next(null);
71
+ }
72
+ // Metadata CRUD
73
+ /** sets the metadata on an account */
74
+ setAccountMetadata(id, metadata) {
75
+ const account = this.getAccount(id);
76
+ if (!account)
77
+ throw new Error("Cant find account with that ID");
78
+ account.metadata = metadata;
79
+ }
80
+ /** Removes all metadata on the account */
81
+ clearAccountMetadata(id) {
82
+ const account = this.getAccount(id);
83
+ if (!account)
84
+ throw new Error("Cant find account with that ID");
85
+ account.metadata = undefined;
86
+ }
87
+ // Serialize / Deserialize
88
+ /** Returns an array of serialized accounts */
89
+ toJSON() {
90
+ return Array.from(Object.values(this.accounts)).map((account) => account.toJSON());
91
+ }
92
+ /**
93
+ * Restores all accounts from an array of serialized accounts
94
+ * NOTE: this will clear all existing accounts
95
+ */
96
+ fromJSON(accounts, quite = false) {
97
+ for (const json of accounts) {
98
+ try {
99
+ const AccountType = this.types.get(json.type);
100
+ if (!AccountType) {
101
+ if (!quite)
102
+ throw new Error(`Missing account type ${json.type}`);
103
+ else
104
+ continue;
105
+ }
106
+ const account = AccountType.fromJSON(json);
107
+ this.addAccount(account);
108
+ }
109
+ catch (error) {
110
+ if (!quite)
111
+ throw error;
112
+ }
113
+ }
114
+ }
2
115
  }
package/dist/types.d.ts CHANGED
@@ -1,19 +1,34 @@
1
1
  import { Nip07Interface } from "applesauce-signer";
2
- export type SerializedAccount<T extends string, S> = {
3
- type: T;
2
+ export type EventTemplate = {
3
+ kind: number;
4
+ content: string;
5
+ tags: string[][];
6
+ created_at: number;
7
+ };
8
+ export type SerializedAccount<SignerData, Metadata extends unknown> = {
9
+ /** Internal account ID */
10
+ id: string;
11
+ /** account type */
12
+ type: string;
13
+ /** local name of the account */
4
14
  name?: string;
15
+ /** pubkey of the account */
5
16
  pubkey: string;
6
- signer: S;
17
+ /** Signer data */
18
+ signer: SignerData;
19
+ /** Extra application specific account metadata */
20
+ metadata?: Metadata;
7
21
  };
8
- export interface IAccount<T extends string, S> extends Nip07Interface {
22
+ export interface IAccount<Signer extends Nip07Interface, SignerData, Metadata extends unknown> extends Nip07Interface {
23
+ id: string;
9
24
  name?: string;
10
25
  pubkey: string;
11
- locked: boolean;
12
- unlock(): Promise<boolean>;
13
- lock(): void;
14
- toJSON(): SerializedAccount<T, S>;
26
+ metadata?: Metadata;
27
+ signer: Signer;
28
+ toJSON(): SerializedAccount<SignerData, Metadata>;
15
29
  }
16
- export interface IAccountConstructor<T extends string, S> {
17
- new (pubkey: string, signer: Nip07Interface): IAccount<T, S>;
18
- fromJSON(json: SerializedAccount<T, S>): IAccount<T, S>;
30
+ export interface IAccountConstructor<Signer extends Nip07Interface, SignerData, Metadata extends unknown> {
31
+ type: string;
32
+ new (pubkey: string, signer: Signer): IAccount<Signer, SignerData, Metadata>;
33
+ fromJSON(json: SerializedAccount<SignerData, Metadata>): IAccount<Signer, SignerData, Metadata>;
19
34
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "applesauce-accounts",
3
- "version": "0.0.0-next-20250124172415",
3
+ "version": "0.0.0-next-20250124224517",
4
4
  "description": "A simple nostr account management system",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@noble/hashes": "^1.5.0",
35
- "applesauce-signer": "0.0.0-next-20250124172415",
35
+ "applesauce-signer": "0.0.0-next-20250124224517",
36
36
  "nanoid": "^5.0.9",
37
37
  "nostr-tools": "^2.10.3",
38
38
  "rxjs": "^7.8.1"