@majikah/majik-message 0.2.21 → 0.3.0
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/dist/core/contacts/errors.d.ts +12 -0
- package/dist/core/contacts/errors.js +27 -0
- package/dist/core/contacts/majik-contact-directory.d.ts +2 -8
- package/dist/core/contacts/majik-contact-directory.js +1 -11
- package/dist/core/contacts/majik-contact-groups.d.ts +185 -0
- package/dist/core/contacts/majik-contact-groups.js +557 -0
- package/dist/core/contacts/majik-contact-manager.d.ts +240 -0
- package/dist/core/contacts/majik-contact-manager.js +449 -0
- package/dist/core/contacts/majik-contact-migration.d.ts +27 -0
- package/dist/core/contacts/majik-contact-migration.js +84 -0
- package/dist/core/contacts/types.d.ts +11 -0
- package/dist/core/contacts/types.js +4 -0
- package/dist/majik-message.d.ts +160 -36
- package/dist/majik-message.js +288 -128
- package/package.json +4 -4
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class MajikContactManagerError extends Error {
|
|
2
|
+
cause?: unknown;
|
|
3
|
+
constructor(message: string, cause?: unknown);
|
|
4
|
+
}
|
|
5
|
+
export declare class MajikContactDirectoryError extends Error {
|
|
6
|
+
cause?: unknown;
|
|
7
|
+
constructor(message: string, cause?: unknown);
|
|
8
|
+
}
|
|
9
|
+
export declare class MajikContactGroupManagerError extends Error {
|
|
10
|
+
cause?: unknown;
|
|
11
|
+
constructor(message: string, cause?: unknown);
|
|
12
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* -------------------------------
|
|
2
|
+
* Errors
|
|
3
|
+
* ------------------------------- */
|
|
4
|
+
export class MajikContactManagerError extends Error {
|
|
5
|
+
cause;
|
|
6
|
+
constructor(message, cause) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = "MajikContactManagerError";
|
|
9
|
+
this.cause = cause;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export class MajikContactDirectoryError extends Error {
|
|
13
|
+
cause;
|
|
14
|
+
constructor(message, cause) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = "MajikContactDirectoryError";
|
|
17
|
+
this.cause = cause;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export class MajikContactGroupManagerError extends Error {
|
|
21
|
+
cause;
|
|
22
|
+
constructor(message, cause) {
|
|
23
|
+
super(message);
|
|
24
|
+
this.name = "MajikContactGroupManagerError";
|
|
25
|
+
this.cause = cause;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -1,13 +1,7 @@
|
|
|
1
1
|
import { MessageEnvelope } from "../messages/message-envelope";
|
|
2
2
|
import { MAJIK_API_RESPONSE } from "../types";
|
|
3
|
-
import { MajikContact, MajikContactData
|
|
4
|
-
|
|
5
|
-
contacts: SerializedMajikContact[];
|
|
6
|
-
}
|
|
7
|
-
export declare class MajikContactDirectoryError extends Error {
|
|
8
|
-
cause?: unknown;
|
|
9
|
-
constructor(message: string, cause?: unknown);
|
|
10
|
-
}
|
|
3
|
+
import { MajikContact, MajikContactData } from "@majikah/majik-contact";
|
|
4
|
+
import { MajikContactDirectoryData } from "./types";
|
|
11
5
|
export declare class MajikContactDirectory {
|
|
12
6
|
private contacts;
|
|
13
7
|
private fingerprintMap;
|
|
@@ -1,17 +1,7 @@
|
|
|
1
1
|
import { KEY_ALGO } from "../crypto/constants";
|
|
2
2
|
import { base64ToArrayBuffer } from "../utils/utilities";
|
|
3
3
|
import { MajikContact, } from "@majikah/majik-contact";
|
|
4
|
-
|
|
5
|
-
* Errors
|
|
6
|
-
* ------------------------------- */
|
|
7
|
-
export class MajikContactDirectoryError extends Error {
|
|
8
|
-
cause;
|
|
9
|
-
constructor(message, cause) {
|
|
10
|
-
super(message);
|
|
11
|
-
this.name = "MajikContactDirectoryError";
|
|
12
|
-
this.cause = cause;
|
|
13
|
-
}
|
|
14
|
-
}
|
|
4
|
+
import { MajikContactDirectoryError } from "./errors";
|
|
15
5
|
/* -------------------------------
|
|
16
6
|
* MajikContactDirectory Class
|
|
17
7
|
* ------------------------------- */
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { MajikContact, MajikContactGroup, MajikContactGroupMeta } from "@majikah/majik-contact";
|
|
2
|
+
import { MajikContactDirectory } from "./majik-contact-directory";
|
|
3
|
+
import { MAJIK_API_RESPONSE } from "../types";
|
|
4
|
+
import { MajikContactGroupManagerData } from "./types";
|
|
5
|
+
/**
|
|
6
|
+
* Manages the full lifecycle of MajikContactGroup instances.
|
|
7
|
+
*
|
|
8
|
+
* Responsibilities:
|
|
9
|
+
* - Owns the canonical Map of all groups (user-created + system groups)
|
|
10
|
+
* - Maintains a reverse index: contactId → Set<groupId> for O(1) group lookups per contact
|
|
11
|
+
* - Hydrates group members into full MajikContact instances via an injected MajikContactDirectory
|
|
12
|
+
* - Automatically syncs system group side-effects (e.g. Blocked group ↔ MajikContact.block())
|
|
13
|
+
* - Provides a handleContactRemoved() hook for MajikContactDirectory to call on contact removal
|
|
14
|
+
* - Handles serialization / deserialization of all groups together
|
|
15
|
+
*
|
|
16
|
+
* System groups (Favorites, Blocked) are always present and are bootstrapped in the constructor.
|
|
17
|
+
* They cannot be deleted or renamed but their membership is fully manageable.
|
|
18
|
+
*/
|
|
19
|
+
export declare class MajikContactGroupManager {
|
|
20
|
+
private groups;
|
|
21
|
+
/**
|
|
22
|
+
* Reverse index: contactId → Set of groupIds the contact belongs to.
|
|
23
|
+
* Kept in sync on every membership mutation so getGroupsForContact() is O(1).
|
|
24
|
+
*/
|
|
25
|
+
private contactGroupIndex;
|
|
26
|
+
private directory;
|
|
27
|
+
constructor(directory: MajikContactDirectory);
|
|
28
|
+
/**
|
|
29
|
+
* Ensures the two system groups always exist on construction.
|
|
30
|
+
* Safe to call multiple times — skips if already present.
|
|
31
|
+
*/
|
|
32
|
+
private bootstrapSystemGroups;
|
|
33
|
+
/**
|
|
34
|
+
* Creates and registers a new user group.
|
|
35
|
+
* Throws if a group with the same ID already exists.
|
|
36
|
+
*/
|
|
37
|
+
createGroup(id: string, name: string, meta?: Partial<Omit<MajikContactGroupMeta, "name">>, initialMemberIds?: string[]): MajikContactGroup;
|
|
38
|
+
/**
|
|
39
|
+
* Registers an already-constructed MajikContactGroup instance.
|
|
40
|
+
* Useful when importing groups from external sources.
|
|
41
|
+
* Throws if a group with the same ID already exists.
|
|
42
|
+
*/
|
|
43
|
+
addGroup(group: MajikContactGroup): this;
|
|
44
|
+
/**
|
|
45
|
+
* Removes a user group by ID.
|
|
46
|
+
* System groups cannot be deleted.
|
|
47
|
+
* Cleans up the reverse index for all former members.
|
|
48
|
+
*/
|
|
49
|
+
removeGroup(id: string): MAJIK_API_RESPONSE;
|
|
50
|
+
getGroup(id: string): MajikContactGroup | undefined;
|
|
51
|
+
getGroupOrThrow(id: string): MajikContactGroup;
|
|
52
|
+
hasGroup(id: string): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Returns all groups, optionally filtered and/or sorted.
|
|
55
|
+
*
|
|
56
|
+
* @param includeSystem Include system groups (Favorites, Blocked). Default: true.
|
|
57
|
+
* @param sortedByName Sort results by group name. Default: false.
|
|
58
|
+
*/
|
|
59
|
+
listGroups(includeSystem?: boolean, sortedByName?: boolean): MajikContactGroup[];
|
|
60
|
+
/**
|
|
61
|
+
* Updates mutable metadata fields on a group.
|
|
62
|
+
* Name is protected on system groups (delegates to MajikContactGroup.updateName which throws).
|
|
63
|
+
*/
|
|
64
|
+
updateGroupMeta(id: string, meta: Partial<Pick<MajikContactGroupMeta, "name" | "description">>): MajikContactGroup;
|
|
65
|
+
/**
|
|
66
|
+
* Adds a contact to a group.
|
|
67
|
+
*
|
|
68
|
+
* - Validates the contact exists in the directory.
|
|
69
|
+
* - If the target group is the system Blocked group, also calls contact.block()
|
|
70
|
+
* on the directory to keep MajikContact state in sync.
|
|
71
|
+
* - Throws if the contact is already a member (strict — use addMemberIfAbsent for idempotent).
|
|
72
|
+
*/
|
|
73
|
+
addContactToGroup(groupId: string, contactId: string): MajikContactGroup;
|
|
74
|
+
/**
|
|
75
|
+
* Idempotent variant — does not throw if the contact is already a member.
|
|
76
|
+
* Still validates contact existence and handles Blocked sync.
|
|
77
|
+
*/
|
|
78
|
+
addContactToGroupIfAbsent(groupId: string, contactId: string): MajikContactGroup;
|
|
79
|
+
/**
|
|
80
|
+
* Adds multiple contacts to a group in one call.
|
|
81
|
+
* All contacts are validated before any mutation is applied (all-or-nothing).
|
|
82
|
+
*/
|
|
83
|
+
addContactsToGroup(groupId: string, contactIds: string[]): MajikContactGroup;
|
|
84
|
+
/**
|
|
85
|
+
* Removes a contact from a group.
|
|
86
|
+
*
|
|
87
|
+
* - If removing from the system Blocked group, also calls contact.unblock()
|
|
88
|
+
* to keep MajikContact state in sync.
|
|
89
|
+
* - Throws if the contact is not a member (strict — use removeContactFromGroupIfPresent for idempotent).
|
|
90
|
+
*/
|
|
91
|
+
removeContactFromGroup(groupId: string, contactId: string): MajikContactGroup;
|
|
92
|
+
/**
|
|
93
|
+
* Idempotent variant — does not throw if the contact is not a member.
|
|
94
|
+
*/
|
|
95
|
+
removeContactFromGroupIfPresent(groupId: string, contactId: string): MajikContactGroup;
|
|
96
|
+
/**
|
|
97
|
+
* Moves a contact from one group to another atomically.
|
|
98
|
+
* Throws if the contact is not a member of the source group.
|
|
99
|
+
*/
|
|
100
|
+
moveContact(contactId: string, fromGroupId: string, toGroupId: string): void;
|
|
101
|
+
/**
|
|
102
|
+
* Returns all group IDs the contact belongs to.
|
|
103
|
+
* O(1) — backed by the reverse index.
|
|
104
|
+
*/
|
|
105
|
+
getGroupIdsForContact(contactId: string): string[];
|
|
106
|
+
/**
|
|
107
|
+
* Returns all groups the contact belongs to as MajikContactGroup instances.
|
|
108
|
+
*/
|
|
109
|
+
getGroupsForContact(contactId: string): MajikContactGroup[];
|
|
110
|
+
/**
|
|
111
|
+
* Returns all hydrated MajikContact instances that are members of the given group.
|
|
112
|
+
* Contacts that exist in the group but have been removed from the directory are silently skipped.
|
|
113
|
+
*/
|
|
114
|
+
getContactsInGroup(groupId: string): MajikContact[];
|
|
115
|
+
/**
|
|
116
|
+
* Returns hydrated contacts that are members of the given group,
|
|
117
|
+
* sorted by their display label (or ID if no label set).
|
|
118
|
+
*/
|
|
119
|
+
getContactsInGroupSorted(groupId: string): MajikContact[];
|
|
120
|
+
/**
|
|
121
|
+
* Returns true if the contact is a member of the given group.
|
|
122
|
+
*/
|
|
123
|
+
isContactInGroup(groupId: string, contactId: string): boolean;
|
|
124
|
+
/**
|
|
125
|
+
* Returns true if the contact is in the system Favorites group.
|
|
126
|
+
*/
|
|
127
|
+
isFavorite(contactId: string): boolean;
|
|
128
|
+
/**
|
|
129
|
+
* Returns true if the contact is in the system Blocked group.
|
|
130
|
+
*/
|
|
131
|
+
isBlocked(contactId: string): boolean;
|
|
132
|
+
addToFavorites(contactId: string): MajikContactGroup;
|
|
133
|
+
removeFromFavorites(contactId: string): MajikContactGroup;
|
|
134
|
+
/**
|
|
135
|
+
* Adds the contact to the Blocked group and calls contact.block() on the directory.
|
|
136
|
+
*/
|
|
137
|
+
blockContact(contactId: string): MajikContactGroup;
|
|
138
|
+
/**
|
|
139
|
+
* Removes the contact from the Blocked group.
|
|
140
|
+
* Calls contact.unblock() only if the contact is not re-blocked by any other mechanism.
|
|
141
|
+
*/
|
|
142
|
+
unblockContact(contactId: string): MajikContactGroup;
|
|
143
|
+
getFavoritesGroup(): MajikContactGroup;
|
|
144
|
+
getBlockedGroup(): MajikContactGroup;
|
|
145
|
+
/**
|
|
146
|
+
* Must be called whenever a contact is removed from MajikContactDirectory.
|
|
147
|
+
* Auto-removes the contact from every group it belongs to and cleans up the reverse index.
|
|
148
|
+
*
|
|
149
|
+
* Usage:
|
|
150
|
+
* const response = directory.removeContact(id);
|
|
151
|
+
* if (response.success) manager.handleContactRemoved(id);
|
|
152
|
+
*/
|
|
153
|
+
handleContactRemoved(contactId: string): void;
|
|
154
|
+
toJSON(): MajikContactGroupManagerData;
|
|
155
|
+
/**
|
|
156
|
+
* Restores all groups from serialized data.
|
|
157
|
+
* Clears existing user groups but preserves system groups (they are re-bootstrapped).
|
|
158
|
+
* Rebuilds the reverse index from scratch.
|
|
159
|
+
*/
|
|
160
|
+
fromJSON(data: MajikContactGroupManagerData): this;
|
|
161
|
+
private indexAdd;
|
|
162
|
+
private indexRemove;
|
|
163
|
+
/**
|
|
164
|
+
* Unblocks a contact on the directory only if the contact is no longer
|
|
165
|
+
* a member of the system Blocked group. Guards against a race where
|
|
166
|
+
* the contact was re-added before unblock is processed.
|
|
167
|
+
*/
|
|
168
|
+
private syncUnblock;
|
|
169
|
+
private assertDirectory;
|
|
170
|
+
private assertGroupId;
|
|
171
|
+
private assertContactId;
|
|
172
|
+
private assertContactIdArray;
|
|
173
|
+
private assertGroupInstance;
|
|
174
|
+
private assertNotSystemId;
|
|
175
|
+
/**
|
|
176
|
+
* Resolves a contact from the directory and throws a descriptive error if not found.
|
|
177
|
+
*/
|
|
178
|
+
private getContactOrThrow;
|
|
179
|
+
/**
|
|
180
|
+
* Validates that all provided contact IDs exist in the directory.
|
|
181
|
+
* Collects all missing IDs and throws once with the full list,
|
|
182
|
+
* rather than failing on the first missing contact.
|
|
183
|
+
*/
|
|
184
|
+
private assertContactsExist;
|
|
185
|
+
}
|