@majikah/majik-message 0.3.6 → 0.3.7

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.
Files changed (66) hide show
  1. package/README.md +3 -3
  2. package/dist/core/client-state-manager.d.ts +105 -0
  3. package/dist/core/client-state-manager.js +250 -0
  4. package/dist/core/contacts/majik-contact-directory.d.ts +0 -5
  5. package/dist/core/contacts/majik-contact-directory.js +0 -12
  6. package/dist/core/contacts/majik-contact-groups.d.ts +1 -0
  7. package/dist/core/contacts/majik-contact-groups.js +5 -0
  8. package/dist/core/contacts/majik-contact-manager.d.ts +92 -184
  9. package/dist/core/contacts/majik-contact-manager.js +368 -288
  10. package/dist/core/crypto/keystore-manager.d.ts +166 -0
  11. package/dist/core/crypto/keystore-manager.js +371 -0
  12. package/dist/core/storage/chats/_types.d.ts +8 -0
  13. package/dist/core/storage/chats/_types.js +1 -0
  14. package/dist/core/storage/chats/adapter-idb.d.ts +3 -0
  15. package/dist/core/storage/chats/adapter-idb.js +5 -0
  16. package/dist/core/storage/chats/adapter-memory.d.ts +23 -0
  17. package/dist/core/storage/chats/adapter-memory.js +44 -0
  18. package/dist/core/storage/chats/adapter-sql.d.ts +17 -0
  19. package/dist/core/storage/chats/adapter-sql.js +84 -0
  20. package/dist/core/storage/client-state/_types.d.ts +37 -0
  21. package/dist/core/storage/client-state/_types.js +16 -0
  22. package/dist/core/storage/client-state/adapter-idb.d.ts +17 -0
  23. package/dist/core/storage/client-state/adapter-idb.js +19 -0
  24. package/dist/core/storage/client-state/adapter-memory.d.ts +20 -0
  25. package/dist/core/storage/client-state/adapter-memory.js +44 -0
  26. package/dist/core/storage/client-state/adapter-sql.d.ts +41 -0
  27. package/dist/core/storage/client-state/adapter-sql.js +104 -0
  28. package/dist/core/storage/contact-directory/contacts/_types.d.ts +3 -0
  29. package/dist/core/storage/contact-directory/contacts/_types.js +1 -0
  30. package/dist/core/storage/contact-directory/contacts/adapter-idb.d.ts +3 -0
  31. package/dist/core/storage/contact-directory/contacts/adapter-idb.js +5 -0
  32. package/dist/core/storage/contact-directory/contacts/adapter-memory.d.ts +14 -0
  33. package/dist/core/storage/contact-directory/contacts/adapter-memory.js +32 -0
  34. package/dist/core/storage/contact-directory/contacts/adapter-sql.d.ts +16 -0
  35. package/dist/core/storage/contact-directory/contacts/adapter-sql.js +73 -0
  36. package/dist/core/storage/contact-directory/groups/_types.d.ts +3 -0
  37. package/dist/core/storage/contact-directory/groups/_types.js +1 -0
  38. package/dist/core/storage/contact-directory/groups/adapter-idb.d.ts +3 -0
  39. package/dist/core/storage/contact-directory/groups/adapter-idb.js +5 -0
  40. package/dist/core/storage/contact-directory/groups/adapter-memory.d.ts +14 -0
  41. package/dist/core/storage/contact-directory/groups/adapter-memory.js +32 -0
  42. package/dist/core/storage/contact-directory/groups/adapter-sql.d.ts +16 -0
  43. package/dist/core/storage/contact-directory/groups/adapter-sql.js +71 -0
  44. package/dist/core/storage/idb-adapter.d.ts +21 -0
  45. package/dist/core/storage/idb-adapter.js +107 -0
  46. package/dist/core/storage/index.d.ts +24 -0
  47. package/dist/core/storage/index.js +19 -0
  48. package/dist/core/storage/keystore/_types.d.ts +3 -0
  49. package/dist/core/storage/keystore/_types.js +1 -0
  50. package/dist/core/storage/keystore/adapter-idb.d.ts +3 -0
  51. package/dist/core/storage/keystore/adapter-idb.js +5 -0
  52. package/dist/core/storage/keystore/adapter-memory.d.ts +14 -0
  53. package/dist/core/storage/keystore/adapter-memory.js +32 -0
  54. package/dist/core/storage/keystore/adapter-sql.d.ts +16 -0
  55. package/dist/core/storage/keystore/adapter-sql.js +69 -0
  56. package/dist/core/storage/sql-db-manager.d.ts +13 -0
  57. package/dist/core/storage/sql-db-manager.js +59 -0
  58. package/dist/core/storage/sql-schema.d.ts +10 -0
  59. package/dist/core/storage/sql-schema.js +108 -0
  60. package/dist/core/storage/storage-adapter.d.ts +14 -0
  61. package/dist/core/storage/storage-adapter.js +1 -0
  62. package/dist/index.d.ts +2 -4
  63. package/dist/index.js +2 -4
  64. package/dist/majik-message.d.ts +109 -174
  65. package/dist/majik-message.js +428 -677
  66. package/package.json +4 -5
@@ -1,29 +1,47 @@
1
1
  import { MajikContact, MajikContactGroup, MajikContactGroupMeta, type MajikContactMeta, type SerializedMajikContact } from "@majikah/majik-contact";
2
2
  import { MessageEnvelope } from "./core/messages/message-envelope";
3
3
  import { EnvelopeCache, type EnvelopeCacheItem, type EnvelopeCacheJSON } from "./core/messages/envelope-cache";
4
- import { MajikKeyStore } from "./core/crypto/keystore";
5
4
  import type { DecryptFileOptions, EncryptFileOptions, EncryptFileResult, MAJIK_API_RESPONSE, MajikMessagePublicKey } from "./core/types";
6
5
  import { MajikMessageChat } from "./core/database/chat/majik-message-chat";
7
6
  import { MajikMessageIdentity } from "./core/database/system/identity";
8
7
  import { MajikKey } from "@majikah/majik-key";
9
8
  import { MajikFile, MajikFileJSON } from "@majikah/majik-file";
10
9
  import { EnvelopeInfo, ExpectedSigner, MajikSignature, SealInfo, SealVerificationResult, SignatoriesFilter, SignatoriesResult, SignatoryInfo, type MajikSignatureJSON, type MajikSignerPublicKeys, type VerificationResult } from "@majikah/majik-signature";
11
- import { MajikContactManager } from "./core/contacts/majik-contact-manager";
10
+ import { MajikContactManager, MajikContactManagerAdapters } from "./core/contacts/majik-contact-manager";
12
11
  import { MajikContactManagerJSON } from "./core/contacts/types";
12
+ import { ClientStateStorageAdapter, MajikKeyStorageAdapter, SQLiteDatabase } from "./core/storage";
13
+ import { MajikKeyManager } from "./core/crypto/keystore-manager";
14
+ import { ClientStateManager } from "./core/client-state-manager";
13
15
  type MajikMessageEvents = "message" | "envelope" | "untrusted" | "error" | "new-account" | "new-contact" | "new-contact-group" | "removed-account" | "removed-contact" | "removed-contact-group" | "contact-group-change" | "active-account-change";
14
- interface MajikMessageStatic<T extends MajikMessage> {
15
- new (config: MajikMessageConfig, id?: string): T;
16
- fromJSON(json: MajikMessageJSON): Promise<T>;
17
- }
18
16
  export interface MajikMessageConfig {
19
- keyStore?: typeof MajikKeyStore;
17
+ dbSQL?: SQLiteDatabase;
20
18
  /**
21
- * Optional pre-constructed MajikContactManager.
22
- * When omitted, MajikMessage creates a fresh one internally.
23
- * Pass one when restoring state from fromJSON() or loadState().
19
+ * Shared contact directory.
20
+ * Pass the same instance used by MajikMessage to keep contacts in sync.
24
21
  */
25
22
  contactManager?: MajikContactManager;
23
+ /**
24
+ * Pre-constructed key manager. If provided, adapters.keys is ignored.
25
+ * Pass the same instance used by MajikMessage / MajikSignatureClient
26
+ * to share a single keystore across clients.
27
+ */
28
+ keyManager?: MajikKeyManager;
26
29
  envelopeCache?: EnvelopeCache;
30
+ /**
31
+ * Pre-constructed client state manager. If provided, adapters.clientState
32
+ * is ignored.
33
+ */
34
+ clientStateManager?: ClientStateManager;
35
+ adapters?: {
36
+ contacts?: MajikContactManagerAdapters;
37
+ keys?: MajikKeyStorageAdapter;
38
+ /**
39
+ * Adapter for client-level state (account order, invoice defaults, etc.).
40
+ * Defaults to IDB_ADAPTER_CLIENT_STATE in browser environments.
41
+ * Pass InMemoryClientStateAdapter for tests or non-browser runtimes.
42
+ */
43
+ clientState?: ClientStateStorageAdapter;
44
+ };
27
45
  }
28
46
  export interface MajikMessageJSON {
29
47
  id: string;
@@ -36,21 +54,48 @@ export interface MajikMessageJSON {
36
54
  }
37
55
  type EventCallback = (...args: any[]) => void;
38
56
  export declare class MajikMessage {
39
- private userProfile;
40
- private id;
41
- private contacts;
57
+ private readonly _id;
58
+ private _db;
59
+ private _contacts;
60
+ private _keys;
61
+ private _state;
42
62
  private envelopeCache;
43
- private listeners;
44
- private ownAccounts;
45
- private ownAccountsOrder;
46
- private autosaveTimer;
47
- private autosaveIntervalId;
48
- private readonly autosaveIntervalMs;
49
- private readonly autosaveDebounceMs;
50
- constructor(config: MajikMessageConfig, id?: string, userProfile?: string);
63
+ private _listeners;
64
+ /** MajikContact instances for accounts this client owns. */
65
+ private _ownAccounts;
66
+ /**
67
+ * Ordered list of own account IDs — head is the active account.
68
+ * Source of truth is ClientStateManager; this array is the in-memory
69
+ * working copy kept in sync on every mutation.
70
+ */
71
+ private _ownAccountsOrder;
72
+ private _autosaveOrderTimer;
73
+ constructor(config: MajikMessageConfig, id?: string);
74
+ /** Expose the key manager so callers can share it with other clients. */
75
+ get keyManager(): MajikKeyManager;
76
+ /** Expose the client state manager for direct access if needed. */
77
+ get stateManager(): ClientStateManager;
78
+ /**
79
+ * Load all domains from their adapters and restore client state.
80
+ * Call once on startup.
81
+ *
82
+ * ```ts
83
+ * const client = new MajikBuwizClient({ adapters: { keys: idbAdapter, ... } });
84
+ * await client.hydrate();
85
+ * ```
86
+ */
87
+ hydrate(): Promise<void>;
88
+ private _hydrateOwnAccounts;
89
+ private _restoreAccountOrder;
90
+ private _scheduleOrderSave;
91
+ private _persistAccountOrder;
92
+ /**
93
+ * Construct a client and immediately hydrate it.
94
+ */
95
+ static create<T extends MajikMessage>(this: new (config: MajikMessageConfig) => T, config?: MajikMessageConfig): Promise<T>;
51
96
  /**
52
97
  * Resolve a list of account/contact IDs into MajikRecipient objects.
53
- * Each recipient needs their ML-KEM public key from MajikKeyStore.
98
+ * Each recipient needs their ML-KEM public key from this.keyManager.
54
99
  */
55
100
  private _resolveRecipientsByPublicKey;
56
101
  /**
@@ -79,180 +124,74 @@ export declare class MajikMessage {
79
124
  private _resolveFileRecipientsByPublicKey;
80
125
  /** Canonical source for the scanner hostname tag. */
81
126
  private get _source();
82
- generateMnemonic(): string;
83
- exportAccountMnemonicBackup(id: string, mnemonic: string): Promise<string>;
84
- /**
85
- * Import an account from a mnemonic-encrypted backup.
86
- * Fully upgrades to Argon2id KDF + ML-KEM keys in one step.
87
- */
127
+ generateMnemonic(strength?: 128 | 256): string;
128
+ createAccount(mnemonic: string, passphrase: string, label?: string): Promise<{
129
+ id: string;
130
+ fingerprint: string;
131
+ backup: string;
132
+ }>;
88
133
  importAccountFromMnemonicBackup(backupBase64: string, mnemonic: string, passphrase: string, label?: string): Promise<{
89
134
  id: string;
90
135
  fingerprint: string;
91
136
  }>;
92
- /**
93
- * Create a new account from a mnemonic, store it encrypted with passphrase.
94
- */
95
- createAccountFromMnemonic(mnemonic: string, passphrase: string, label?: string): Promise<{
137
+ replaceAccountFromMnemonicBackup(backupBase64: string, mnemonic: string, passphrase: string, label?: string): Promise<{
96
138
  id: string;
97
139
  fingerprint: string;
98
- backup: string;
99
140
  }>;
141
+ exportAccountMnemonicBackup(id: string, mnemonic: string): Promise<string>;
100
142
  addOwnAccount(account: MajikContact): void;
101
- listOwnAccounts(majikahOnly?: boolean): MajikContact[];
143
+ removeOwnAccount(id: string): Promise<boolean>;
102
144
  getOwnAccountById(id: string): MajikContact | undefined;
103
- setActiveAccount(id: string, bypassIdentity?: boolean): Promise<boolean>;
104
145
  getActiveAccount(): MajikContact | null;
146
+ getActiveAccountKey(): MajikKey | null;
105
147
  isAccountActive(id: string): boolean;
106
- removeOwnAccount(id: string): boolean;
148
+ setActiveAccount(id: string, bypassIdentity?: boolean): Promise<boolean>;
149
+ listOwnAccounts(majikahOnly?: boolean): MajikContact[];
150
+ isContactMajikahRegistered(id: string): boolean;
151
+ isContactMajikahIdentityChecked(id: string): boolean;
152
+ setContactMajikahStatus(id: string, status: boolean): void;
107
153
  hasOwnIdentity(fingerprint: string): Promise<boolean>;
108
- updatePassphrase(currentPassphrase: string, newPassphrase: string, id?: string): Promise<void>;
109
154
  getContactByID(id: string): MajikContact | null;
110
- hasContact(id: string): boolean;
111
- hasContactByPublicKeyBase64(publicKey: MajikMessagePublicKey): Promise<boolean>;
112
- getContactByPublicKey(publicKeyBase64: MajikMessagePublicKey): Promise<MajikContact | null>;
113
- exportContactAsJSON(contactID: string): Promise<string | null>;
114
- exportContactAsString(contactID: string): Promise<string | null>;
155
+ getContactByPublicKey(publicKeyBase64: string): Promise<MajikContact | null>;
156
+ exportContactAsJSON(id: string): Promise<string | null>;
157
+ exportContactAsString(id: string): Promise<string | null>;
115
158
  importContactFromJSON(jsonStr: string): Promise<MAJIK_API_RESPONSE>;
116
159
  importContactFromString(base64Str: string): Promise<MAJIK_API_RESPONSE>;
117
160
  exportContactCompressed(contact: MajikContact): Promise<string>;
118
161
  importContactCompressed(base64Str: string): Promise<MajikContact>;
119
- addContact(contact: MajikContact): void;
120
- removeContact(id: string): void;
121
- updateContactMeta(id: string, meta: Partial<MajikContactMeta>): void;
122
- blockContact(id: string): void;
123
- unblockContact(id: string): void;
124
- listContacts(all?: boolean, majikahOnly?: boolean): MajikContact[];
125
- isContactMajikahRegistered(id: string): boolean;
126
- isContactMajikahIdentityChecked(id: string): boolean;
127
- setContactMajikahStatus(id: string, status: boolean): void;
128
- /**
129
- * Creates and registers a new user-defined group.
130
- * Throws if a group with the same ID already exists.
131
- */
132
- createGroup(id: string, name: string, meta?: Partial<Omit<MajikContactGroupMeta, "name">>, initialMemberIds?: string[]): this;
133
- /**
134
- * Registers an already-constructed MajikContactGroup instance.
135
- * Throws if a group with the same ID already exists.
136
- */
137
- addGroup(group: MajikContactGroup): this;
138
- /**
139
- * Removes a user group by ID.
140
- * System groups (Favorites, Blocked) cannot be deleted.
141
- */
142
- removeGroup(id: string): MAJIK_API_RESPONSE;
143
- /**
144
- * Returns a group by ID, or undefined if not found.
145
- */
162
+ addContact(contact: MajikContact): Promise<void>;
163
+ removeContact(id: string): Promise<void>;
164
+ listContacts(includeOwnAccounts?: boolean): MajikContact[];
165
+ updateContactMeta(id: string, meta: Partial<MajikContactMeta>): Promise<void>;
166
+ createGroup(id: string, name: string, meta?: Partial<Omit<MajikContactGroupMeta, "name">>, initialMemberIds?: string[]): Promise<this>;
167
+ addGroup(group: MajikContactGroup): Promise<this>;
168
+ removeGroup(id: string): Promise<MAJIK_API_RESPONSE>;
146
169
  getContactGroup(id: string): MajikContactGroup | undefined;
147
- /**
148
- * Returns a group by ID. Throws if not found.
149
- */
150
170
  getGroupOrThrow(id: string): MajikContactGroup;
151
- /**
152
- * Returns true if a group with the given ID exists.
153
- */
154
171
  hasGroup(id: string): boolean;
155
- /**
156
- * Returns all groups.
157
- *
158
- * @param includeSystem Include system groups (Favorites, Blocked). Default: true.
159
- * @param sortedByName Sort results alphabetically by group name. Default: false.
160
- */
161
172
  listContactGroups(includeSystem?: boolean, sortedByName?: boolean): MajikContactGroup[];
162
- /**
163
- * Returns only user-created groups (excludes Favorites and Blocked).
164
- * Sorted alphabetically by name.
165
- */
166
173
  listUserGroups(sortedByName?: boolean): MajikContactGroup[];
167
- /**
168
- * Returns only system groups (Favorites and Blocked).
169
- */
170
174
  listSystemGroups(): MajikContactGroup[];
171
- /**
172
- * Updates mutable metadata on a group (name, description).
173
- * Name is locked on system groups — will throw if attempted.
174
- */
175
- updateGroupMeta(id: string, meta: Partial<Pick<MajikContactGroupMeta, "name" | "description" | "color">>): this;
176
- /**
177
- * Adds a contact to a group.
178
- * Validates the contact exists in the directory.
179
- * If the group is the system Blocked group, also calls contact.block().
180
- * Throws if the contact is already a member — use addContactToGroupIfAbsent for idempotent.
181
- */
182
- addContactToGroup(groupID: string, contactID: string): this;
183
- /**
184
- * Adds multiple contacts to a group in one call (all-or-nothing).
185
- */
186
- addContactsToGroup(groupID: string, contactIds: string[]): this;
187
- /**
188
- * Removes a contact from a group.
189
- * If the group is the system Blocked group, also calls contact.unblock().
190
- * Throws if the contact is not a member — use removeContactFromGroupIfPresent for idempotent.
191
- */
192
- removeContactFromGroup(groupID: string, contactID: string): this;
193
- /**
194
- * Moves a contact from one group to another atomically.
195
- * Throws if the contact is not a member of the source group.
196
- */
197
- moveContactBetweenGroups(contactID: string, fromGroupId: string, toGroupId: string): this;
198
- /**
199
- * Returns all hydrated MajikContact instances in the given group.
200
- * Contacts removed from the directory since last save are silently skipped.
201
- */
175
+ updateGroupMeta(id: string, meta: Partial<Pick<MajikContactGroupMeta, "name" | "description" | "color">>): Promise<this>;
176
+ addContactToGroup(groupID: string, contactID: string): Promise<this>;
177
+ addContactsToGroup(groupID: string, contactIds: string[]): Promise<this>;
178
+ removeContactFromGroup(groupID: string, contactID: string): Promise<this>;
179
+ moveContactBetweenGroups(contactID: string, fromGroupId: string, toGroupId: string): Promise<this>;
202
180
  getContactsInGroup(groupID: string): MajikContact[];
203
- /**
204
- * Returns hydrated contacts in the group, sorted by label (or ID if no label).
205
- */
206
181
  getContactsInGroupSorted(groupID: string): MajikContact[];
207
- /**
208
- * Returns true if the contact is a member of the given group.
209
- */
210
182
  isContactInGroup(groupID: string, contactID: string): boolean;
211
- /**
212
- * Returns all groups the contact belongs to.
213
- */
214
183
  getGroupsForContact(contactID: string): MajikContactGroup[];
215
- /**
216
- * Returns all group IDs the contact belongs to.
217
- */
218
184
  getGroupIdsForContact(contactID: string): string[];
219
- /**
220
- * Adds the contact to the Favorites group (idempotent).
221
- */
222
- addContactToFavorites(contactID: string): this;
223
- /**
224
- * Removes the contact from the Favorites group (idempotent).
225
- */
226
- removeContactFromFavorites(contactID: string): this;
227
- /**
228
- * Returns true if the contact is in the Favorites group.
229
- */
185
+ addContactToFavorites(contactID: string): Promise<this>;
186
+ removeContactFromFavorites(contactID: string): Promise<this>;
230
187
  isContactFavorite(contactID: string): boolean;
231
- /**
232
- * Returns true if the contact is in the Blocked group.
233
- */
234
188
  isContactBlocked(contactID: string): boolean;
235
- /**
236
- * Returns the Favorites system group instance.
237
- */
238
189
  getFavoritesGroup(): MajikContactGroup;
239
- /**
240
- * Returns the Blocked system group instance.
241
- */
242
190
  getBlockedGroup(): MajikContactGroup;
243
- /**
244
- * Returns all contacts in the Favorites group as hydrated MajikContact instances.
245
- */
246
191
  getFavoriteContacts(): MajikContact[];
247
- /**
248
- * Returns all contacts in the Blocked group as hydrated MajikContact instances.
249
- */
250
192
  getBlockedContacts(): MajikContact[];
251
- /**
252
- * Clears both the directory and all group memberships.
253
- * System groups are preserved (re-bootstrapped by the group manager).
254
- */
255
- clearDirectory(): this;
193
+ clearDirectory(): Promise<this>;
194
+ resolveSignerLabel(signerId: string): string;
256
195
  /**
257
196
  * Compose and encrypt a message for one or more recipients.
258
197
  * Single recipient → solo envelope. Two or more → group envelope.
@@ -680,7 +619,7 @@ export declare class MajikMessage {
680
619
  clearCachedEnvelopes(): Promise<boolean>;
681
620
  /**
682
621
  * Ensure an identity is unlocked.
683
- * Delegates entirely to MajikKeyStore.ensureUnlocked() — passphrase prompting
622
+ * Delegates entirely to this.keyManager.ensureUnlocked() — passphrase prompting
684
623
  * is handled there via onUnlockRequested or the optional promptFn.
685
624
  */
686
625
  ensureIdentityUnlocked(id: string, promptFn?: (id: string) => string | Promise<string>): Promise<CryptoKey | {
@@ -689,7 +628,7 @@ export declare class MajikMessage {
689
628
  isPassphraseValid(passphrase: string, id?: string): Promise<boolean>;
690
629
  on(event: MajikMessageEvents, callback: EventCallback): void;
691
630
  off(event: MajikMessageEvents, callback?: EventCallback): void;
692
- private emit;
631
+ private _emit;
693
632
  /**
694
633
  * Sign raw bytes or a string using the active account.
695
634
  *
@@ -1123,15 +1062,11 @@ export declare class MajikMessage {
1123
1062
  * throughout MajikMessage — consistent account/contact resolution in one place.
1124
1063
  */
1125
1064
  private _resolveSignerPublicKeys;
1126
- toJSON(): Promise<MajikMessageJSON>;
1127
- static fromJSON<T extends MajikMessage>(this: new (config: MajikMessageConfig, id?: string) => T, json: MajikMessageJSON): Promise<T>;
1128
- private attachAutosaveHandlers;
1129
- startAutosave(): void;
1130
- stopAutosave(): void;
1131
- private scheduleAutosave;
1132
- saveState(): Promise<void>;
1133
- loadState(): Promise<void>;
1134
- static loadOrCreate<T extends MajikMessage>(this: MajikMessageStatic<T>, config: MajikMessageConfig, userProfile?: string): Promise<T>;
1135
- resetData(userProfile?: string): Promise<void>;
1065
+ /**
1066
+ * Wipe all data from every adapter and reset in-memory state.
1067
+ * The client remains usable — call hydrate() or add new accounts after reset.
1068
+ */
1069
+ resetData(): Promise<void>;
1070
+ private _registerOwnAccount;
1136
1071
  }
1137
1072
  export {};