@thezelijah/majik-message 1.1.2 → 1.1.3
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.
|
@@ -57,7 +57,6 @@ export function deriveKeyFromMnemonic(mnemonic, salt, iterations = 200000, keyLe
|
|
|
57
57
|
return deriveKey(SHA256, m, salt, iterations, keyLen);
|
|
58
58
|
}
|
|
59
59
|
export function x25519SharedSecret(privRaw, pubRaw) {
|
|
60
|
-
// Use @stablelib/x25519 for scalar multiplication / shared secret
|
|
61
60
|
const priv = new Uint8Array(privRaw);
|
|
62
61
|
const pub = new Uint8Array(pubRaw);
|
|
63
62
|
if (x25519.scalarMult) {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { ThreadStatus } from "./enums";
|
|
2
|
-
import { ISODateString, MajikMessagePublicKey, MajikMessageThreadID } from "../../types";
|
|
2
|
+
import { ISODateString, MajikMessageAccountID, MajikMessagePublicKey, MajikMessageThreadID } from "../../types";
|
|
3
3
|
import { MajikUserID } from "@thezelijah/majik-user";
|
|
4
|
+
import { MajikMessageMailJSON } from "./mail/majik-message-mail";
|
|
5
|
+
import { MajikMessageIdentity } from "../system/identity";
|
|
4
6
|
export interface ThreadMetadata {
|
|
5
7
|
title?: string;
|
|
6
8
|
subject?: string;
|
|
@@ -17,7 +19,7 @@ export interface DeletionApproval {
|
|
|
17
19
|
}
|
|
18
20
|
export interface MajikMessageThreadAnalytics {
|
|
19
21
|
threadID: MajikMessageThreadID;
|
|
20
|
-
owner:
|
|
22
|
+
owner: MajikMessageAccountID;
|
|
21
23
|
userID: MajikUserID;
|
|
22
24
|
participantCount: number;
|
|
23
25
|
messageCount: number;
|
|
@@ -28,6 +30,7 @@ export interface MajikMessageThreadAnalytics {
|
|
|
28
30
|
tags: string[];
|
|
29
31
|
category: string | undefined;
|
|
30
32
|
priority: string | undefined;
|
|
33
|
+
starred: boolean;
|
|
31
34
|
deletionStatus: {
|
|
32
35
|
isPendingDeletion: boolean;
|
|
33
36
|
isMarkedForDeletion: boolean;
|
|
@@ -36,16 +39,28 @@ export interface MajikMessageThreadAnalytics {
|
|
|
36
39
|
totalParticipants: number;
|
|
37
40
|
};
|
|
38
41
|
}
|
|
42
|
+
export interface MajikMessageThreadSummary {
|
|
43
|
+
id: MajikMessageThreadID;
|
|
44
|
+
participants: MajikMessagePublicKey[];
|
|
45
|
+
participant_count: number;
|
|
46
|
+
latest_message: MajikMessageMailJSON;
|
|
47
|
+
latest_message_timestamp: ISODateString;
|
|
48
|
+
total_messages: number;
|
|
49
|
+
unread_count: number;
|
|
50
|
+
has_unread: boolean;
|
|
51
|
+
starred: boolean;
|
|
52
|
+
}
|
|
39
53
|
export interface MajikMessageThreadJSON {
|
|
40
54
|
id: MajikMessageThreadID;
|
|
41
|
-
user_id:
|
|
42
|
-
owner:
|
|
55
|
+
user_id: MajikUserID;
|
|
56
|
+
owner: MajikMessageAccountID;
|
|
43
57
|
metadata: ThreadMetadata;
|
|
44
58
|
timestamp: ISODateString;
|
|
45
59
|
participants: string[];
|
|
46
60
|
status: ThreadStatus;
|
|
47
61
|
hash: string;
|
|
48
|
-
deletion_approvals
|
|
62
|
+
deletion_approvals: DeletionApproval[];
|
|
63
|
+
starred: boolean;
|
|
49
64
|
}
|
|
50
65
|
export declare class MajikThreadError extends Error {
|
|
51
66
|
code: string;
|
|
@@ -67,6 +82,7 @@ export declare class MajikMessageThread {
|
|
|
67
82
|
private _status;
|
|
68
83
|
private readonly _hash;
|
|
69
84
|
private _deletionApprovals;
|
|
85
|
+
private _starred;
|
|
70
86
|
private constructor();
|
|
71
87
|
get id(): MajikMessageThreadID;
|
|
72
88
|
get userID(): MajikUserID;
|
|
@@ -77,7 +93,21 @@ export declare class MajikMessageThread {
|
|
|
77
93
|
get status(): ThreadStatus;
|
|
78
94
|
get hash(): string;
|
|
79
95
|
get deletionApprovals(): readonly DeletionApproval[];
|
|
80
|
-
|
|
96
|
+
get starred(): boolean;
|
|
97
|
+
static create(userID: MajikUserID, owner: MajikMessageIdentity, participants: MajikMessagePublicKey[], metadata?: ThreadMetadata): MajikMessageThread;
|
|
98
|
+
/**
|
|
99
|
+
* Stars the thread for the user
|
|
100
|
+
*/
|
|
101
|
+
star(): void;
|
|
102
|
+
/**
|
|
103
|
+
* Unstars the thread for the user
|
|
104
|
+
*/
|
|
105
|
+
unstar(): void;
|
|
106
|
+
/**
|
|
107
|
+
* Toggles the starred status of the thread
|
|
108
|
+
* @returns The new starred state
|
|
109
|
+
*/
|
|
110
|
+
toggleStar(): boolean;
|
|
81
111
|
private static generateHash;
|
|
82
112
|
private static generateApprovalHash;
|
|
83
113
|
validate(): boolean;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { v4 as uuidv4 } from "uuid";
|
|
2
|
-
import * as crypto from "crypto";
|
|
3
2
|
import { ThreadStatus } from "./enums";
|
|
4
3
|
import { sha256 } from "../../crypto/crypto-provider";
|
|
5
4
|
// ==================== Custom Errors ====================
|
|
@@ -27,15 +26,16 @@ export class OperationNotAllowedError extends MajikThreadError {
|
|
|
27
26
|
export class MajikMessageThread {
|
|
28
27
|
_id;
|
|
29
28
|
_userID;
|
|
30
|
-
_owner; // Owner's
|
|
29
|
+
_owner; // Owner's identity account ID
|
|
31
30
|
_metadata;
|
|
32
31
|
_timestamp;
|
|
33
32
|
_participants;
|
|
34
33
|
_status;
|
|
35
34
|
_hash;
|
|
36
35
|
_deletionApprovals;
|
|
36
|
+
_starred;
|
|
37
37
|
// ==================== Private Constructor ====================
|
|
38
|
-
constructor(id, userID, owner, metadata, timestamp, participants, status, hash, deletionApprovals = []) {
|
|
38
|
+
constructor(id, userID, owner, metadata, timestamp, participants, status, hash, deletionApprovals = [], starred = false) {
|
|
39
39
|
this._id = id;
|
|
40
40
|
this._userID = userID;
|
|
41
41
|
this._owner = owner;
|
|
@@ -45,6 +45,7 @@ export class MajikMessageThread {
|
|
|
45
45
|
this._status = status;
|
|
46
46
|
this._hash = hash;
|
|
47
47
|
this._deletionApprovals = deletionApprovals;
|
|
48
|
+
this._starred = starred;
|
|
48
49
|
// Validate on construction
|
|
49
50
|
this.validate();
|
|
50
51
|
}
|
|
@@ -76,6 +77,9 @@ export class MajikMessageThread {
|
|
|
76
77
|
get deletionApprovals() {
|
|
77
78
|
return [...this._deletionApprovals];
|
|
78
79
|
}
|
|
80
|
+
get starred() {
|
|
81
|
+
return this._starred;
|
|
82
|
+
}
|
|
79
83
|
// ==================== Static Create Method ====================
|
|
80
84
|
static create(userID, owner, participants, metadata = {}) {
|
|
81
85
|
try {
|
|
@@ -88,7 +92,7 @@ export class MajikMessageThread {
|
|
|
88
92
|
}
|
|
89
93
|
// Normalize participants (deduplicate + sort)
|
|
90
94
|
const uniqueParticipants = MajikMessageThread.normalizeParticipants([
|
|
91
|
-
owner,
|
|
95
|
+
owner.publicKey,
|
|
92
96
|
...participants,
|
|
93
97
|
]);
|
|
94
98
|
// Validate all participants
|
|
@@ -104,7 +108,7 @@ export class MajikMessageThread {
|
|
|
104
108
|
const status = ThreadStatus.ONGOING;
|
|
105
109
|
// Generate hash
|
|
106
110
|
const hash = MajikMessageThread.generateHash(userID, timestamp, id, uniqueParticipants);
|
|
107
|
-
return new MajikMessageThread(id, userID, owner, metadata, timestamp, uniqueParticipants, status, hash, []);
|
|
111
|
+
return new MajikMessageThread(id, userID, owner.id, metadata, timestamp, uniqueParticipants, status, hash, []);
|
|
108
112
|
}
|
|
109
113
|
catch (error) {
|
|
110
114
|
if (error instanceof MajikThreadError) {
|
|
@@ -113,6 +117,54 @@ export class MajikMessageThread {
|
|
|
113
117
|
throw new MajikThreadError(`Failed to create MajikMessageThread: ${error instanceof Error ? error.message : "Unknown error"}`, "CREATE_FAILED");
|
|
114
118
|
}
|
|
115
119
|
}
|
|
120
|
+
// ==================== Star Management ====================
|
|
121
|
+
/**
|
|
122
|
+
* Stars the thread for the user
|
|
123
|
+
*/
|
|
124
|
+
star() {
|
|
125
|
+
try {
|
|
126
|
+
if (this._starred) {
|
|
127
|
+
throw new OperationNotAllowedError("Thread is already starred");
|
|
128
|
+
}
|
|
129
|
+
this._starred = true;
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
if (error instanceof MajikThreadError) {
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
throw new MajikThreadError(`Failed to star thread: ${error instanceof Error ? error.message : "Unknown error"}`, "STAR_FAILED");
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Unstars the thread for the user
|
|
140
|
+
*/
|
|
141
|
+
unstar() {
|
|
142
|
+
try {
|
|
143
|
+
if (!this._starred) {
|
|
144
|
+
throw new OperationNotAllowedError("Thread is not starred");
|
|
145
|
+
}
|
|
146
|
+
this._starred = false;
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
if (error instanceof MajikThreadError) {
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
throw new MajikThreadError(`Failed to unstar thread: ${error instanceof Error ? error.message : "Unknown error"}`, "UNSTAR_FAILED");
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Toggles the starred status of the thread
|
|
157
|
+
* @returns The new starred state
|
|
158
|
+
*/
|
|
159
|
+
toggleStar() {
|
|
160
|
+
if (this._starred) {
|
|
161
|
+
this.unstar();
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
this.star();
|
|
165
|
+
}
|
|
166
|
+
return this._starred;
|
|
167
|
+
}
|
|
116
168
|
// ==================== Hash Generation ====================
|
|
117
169
|
static generateHash(userID, timestamp, id, participants) {
|
|
118
170
|
// Normalize participants (they should already be normalized, but ensure consistency)
|
|
@@ -124,7 +176,7 @@ export class MajikMessageThread {
|
|
|
124
176
|
}
|
|
125
177
|
static generateApprovalHash(publicKey, threadID, timestamp) {
|
|
126
178
|
const dataString = `${publicKey}:${threadID}:${timestamp.toISOString()}`;
|
|
127
|
-
return
|
|
179
|
+
return sha256(dataString);
|
|
128
180
|
}
|
|
129
181
|
// ==================== Validation ====================
|
|
130
182
|
validate() {
|
|
@@ -422,10 +474,13 @@ export class MajikMessageThread {
|
|
|
422
474
|
participants: [...this._participants],
|
|
423
475
|
status: this._status,
|
|
424
476
|
hash: this._hash,
|
|
425
|
-
deletion_approvals: this._deletionApprovals.
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
477
|
+
deletion_approvals: this._deletionApprovals.length > 0
|
|
478
|
+
? this._deletionApprovals.map((approval) => ({
|
|
479
|
+
...approval,
|
|
480
|
+
timestamp: approval.timestamp,
|
|
481
|
+
}))
|
|
482
|
+
: [],
|
|
483
|
+
starred: this._starred,
|
|
429
484
|
};
|
|
430
485
|
}
|
|
431
486
|
static fromJSON(json) {
|
|
@@ -441,7 +496,7 @@ export class MajikMessageThread {
|
|
|
441
496
|
...approval,
|
|
442
497
|
timestamp: new Date(approval.timestamp),
|
|
443
498
|
}));
|
|
444
|
-
return new MajikMessageThread(data.id, data.user_id, data.owner, data.metadata, timestamp, data.participants, data.status, data.hash, deletionApprovals);
|
|
499
|
+
return new MajikMessageThread(data.id, data.user_id, data.owner, data.metadata, timestamp, data.participants, data.status, data.hash, deletionApprovals, data.starred);
|
|
445
500
|
}
|
|
446
501
|
catch (error) {
|
|
447
502
|
if (error instanceof MajikThreadError) {
|
|
@@ -527,6 +582,7 @@ export class MajikMessageThread {
|
|
|
527
582
|
...approval,
|
|
528
583
|
timestamp: approval.timestamp,
|
|
529
584
|
})),
|
|
585
|
+
starred: this._starred,
|
|
530
586
|
};
|
|
531
587
|
// If we're auto-closing and status changed, actually update the instance
|
|
532
588
|
if (autoClose &&
|
|
@@ -575,6 +631,7 @@ export class MajikMessageThread {
|
|
|
575
631
|
approvedCount: this._deletionApprovals.length,
|
|
576
632
|
totalParticipants: this._participants.length,
|
|
577
633
|
},
|
|
634
|
+
starred: this._starred,
|
|
578
635
|
};
|
|
579
636
|
}
|
|
580
637
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -15,3 +15,6 @@ export * from "./core/database/chat/majik-message-chat";
|
|
|
15
15
|
export type * from "./core/database/chat/types";
|
|
16
16
|
export * from "./core/database/system/identity";
|
|
17
17
|
export * from "./core/compressor/majik-compressor";
|
|
18
|
+
export * from "./core/database/thread/majik-message-thread";
|
|
19
|
+
export * from "./core/database/thread/mail/majik-message-mail";
|
|
20
|
+
export * from "./core/database/thread/enums";
|
package/dist/index.js
CHANGED
|
@@ -13,3 +13,6 @@ export * from "./core/utils/utilities";
|
|
|
13
13
|
export * from "./core/database/chat/majik-message-chat";
|
|
14
14
|
export * from "./core/database/system/identity";
|
|
15
15
|
export * from "./core/compressor/majik-compressor";
|
|
16
|
+
export * from "./core/database/thread/majik-message-thread";
|
|
17
|
+
export * from "./core/database/thread/mail/majik-message-mail";
|
|
18
|
+
export * from "./core/database/thread/enums";
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@thezelijah/majik-message",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"description": "Encrypt and decrypt messages on any website. Secure chats with keypairs and seed-based accounts. Open source.",
|
|
5
|
-
"version": "1.1.
|
|
5
|
+
"version": "1.1.3",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"author": "Zelijah",
|
|
8
8
|
"main": "./dist/index.js",
|
|
@@ -15,6 +15,10 @@
|
|
|
15
15
|
"type": "git",
|
|
16
16
|
"url": "git+https://github.com/jedlsf/majik-message.git"
|
|
17
17
|
},
|
|
18
|
+
"funding": {
|
|
19
|
+
"type": "github",
|
|
20
|
+
"url": "https://github.com/sponsors/jedlsf"
|
|
21
|
+
},
|
|
18
22
|
"keywords": [
|
|
19
23
|
"majik",
|
|
20
24
|
"majik-message",
|