@msssystems/mss-link-sdk 0.1.12 → 0.2.1
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/client/browser-client.d.ts +16 -0
- package/dist/client/browser-client.js +35 -0
- package/dist/client/index.d.ts +3 -20
- package/dist/client/index.js +3 -20
- package/dist/client/mss-link-client.d.ts +12 -0
- package/dist/client/mss-link-client.js +17 -0
- package/dist/client/wasm-client.types.d.ts +1 -1
- package/dist/contracts/chat.contract.d.ts +189 -0
- package/dist/contracts/user-search.contract.d.ts +9 -0
- package/dist/core/http-client.d.ts +24 -0
- package/dist/core/http-client.js +80 -0
- package/dist/{client → core}/local-crypto-health.contracts.d.ts +1 -1
- package/dist/{client → core}/local-crypto-health.js +1 -1
- package/dist/core/wasm-crypto-engine.d.ts +34 -0
- package/dist/core/wasm-crypto-engine.js +75 -0
- package/dist/errors/api-error.d.ts +6 -0
- package/dist/errors/api-error.js +11 -0
- package/dist/errors/sdk-error.d.ts +3 -0
- package/dist/errors/sdk-error.js +6 -0
- package/dist/modules/chats/chats.client.d.ts +11 -0
- package/dist/modules/chats/chats.client.js +25 -0
- package/dist/modules/media/media-crypto.client.d.ts +10 -0
- package/dist/modules/media/media-crypto.client.js +90 -0
- package/dist/{client → modules/messages}/message-decryption-state.js +1 -1
- package/dist/{client → modules/messages}/message-decryption.contracts.d.ts +1 -1
- package/dist/modules/messages/messages-crypto.client.d.ts +14 -0
- package/dist/modules/messages/messages-crypto.client.js +34 -0
- package/dist/modules/messages/messages.client.d.ts +8 -0
- package/dist/modules/messages/messages.client.js +24 -0
- package/dist/{client → modules/storage}/drive-file-runtime.contracts.d.ts +2 -2
- package/dist/{client → modules/storage}/drive-file-runtime.d.ts +1 -1
- package/dist/modules/storage/drive-sharing.contracts.js +1 -0
- package/dist/modules/storage/storage-crypto.client.d.ts +13 -0
- package/dist/modules/storage/storage-crypto.client.js +73 -0
- package/dist/modules/storage/storage-metadata-crypto.contracts.js +1 -0
- package/package.json +1 -1
- package/dist/client/mss-link-browser-client.d.ts +0 -46
- package/dist/client/mss-link-browser-client.js +0 -259
- /package/dist/{client/drive-file-runtime.contracts.js → contracts/chat.contract.js} +0 -0
- /package/dist/{client/drive-key-wrapping.contracts.js → contracts/user-search.contract.js} +0 -0
- /package/dist/{client → core}/api-base-url.d.ts +0 -0
- /package/dist/{client → core}/api-base-url.js +0 -0
- /package/dist/{client → core}/local-crypto-health.contracts.js +0 -0
- /package/dist/{client → core}/local-crypto-health.d.ts +0 -0
- /package/dist/{client → core}/wasm-call-queue.d.ts +0 -0
- /package/dist/{client → core}/wasm-call-queue.js +0 -0
- /package/dist/{client → errors}/decryption-errors.d.ts +0 -0
- /package/dist/{client → errors}/decryption-errors.js +0 -0
- /package/dist/{client → modules/media}/media-crypto.contracts.d.ts +0 -0
- /package/dist/{client → modules/media}/media-crypto.contracts.js +0 -0
- /package/dist/{client → modules/media}/media-message-metadata.d.ts +0 -0
- /package/dist/{client → modules/media}/media-message-metadata.js +0 -0
- /package/dist/{client → modules/media}/media-message.contracts.d.ts +0 -0
- /package/dist/{client → modules/media}/media-message.contracts.js +0 -0
- /package/dist/{client → modules/messages}/message-decryption-state.d.ts +0 -0
- /package/dist/{client → modules/messages}/message-decryption.contracts.js +0 -0
- /package/dist/{client → modules/messages}/message.contracts.d.ts +0 -0
- /package/dist/{client → modules/messages}/message.contracts.js +0 -0
- /package/dist/{client → modules/messages}/message.mapper.d.ts +0 -0
- /package/dist/{client → modules/messages}/message.mapper.js +0 -0
- /package/dist/{client/drive-sharing.contracts.js → modules/storage/drive-file-runtime.contracts.js} +0 -0
- /package/dist/{client → modules/storage}/drive-file-runtime.js +0 -0
- /package/dist/{client → modules/storage}/drive-key-wrapping.contracts.d.ts +0 -0
- /package/dist/{client/storage-metadata-crypto.contracts.js → modules/storage/drive-key-wrapping.contracts.js} +0 -0
- /package/dist/{client → modules/storage}/drive-key-wrapping.d.ts +0 -0
- /package/dist/{client → modules/storage}/drive-key-wrapping.js +0 -0
- /package/dist/{client → modules/storage}/drive-sharing.contracts.d.ts +0 -0
- /package/dist/{client → modules/storage}/drive-sharing.d.ts +0 -0
- /package/dist/{client → modules/storage}/drive-sharing.js +0 -0
- /package/dist/{client → modules/storage}/storage-metadata-crypto.contracts.d.ts +0 -0
- /package/dist/{client → modules/storage}/storage-metadata-crypto.d.ts +0 -0
- /package/dist/{client → modules/storage}/storage-metadata-crypto.js +0 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { MssLinkClient, MssLinkClientOptions } from './mss-link-client';
|
|
2
|
+
import { WasmCryptoEngine, WasmCryptoEngineOptions } from '../core/wasm-crypto-engine';
|
|
3
|
+
import { MessagesCryptoClient } from '../modules/messages/messages-crypto.client';
|
|
4
|
+
import { StorageCryptoClient } from '../modules/storage/storage-crypto.client';
|
|
5
|
+
import { MediaCryptoClient } from '../modules/media/media-crypto.client';
|
|
6
|
+
export interface BrowserClientOptions extends MssLinkClientOptions, Omit<WasmCryptoEngineOptions, 'apiBaseUrl' | 'accessToken'> {
|
|
7
|
+
}
|
|
8
|
+
export declare class BrowserMssLinkClient extends MssLinkClient {
|
|
9
|
+
readonly cryptoEngine: WasmCryptoEngine;
|
|
10
|
+
readonly messagesCrypto: MessagesCryptoClient;
|
|
11
|
+
readonly storageCrypto: StorageCryptoClient;
|
|
12
|
+
readonly mediaCrypto: MediaCryptoClient;
|
|
13
|
+
constructor(options: BrowserClientOptions);
|
|
14
|
+
setToken(token: string): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export declare function createBrowserClient(options: BrowserClientOptions): BrowserMssLinkClient;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { MssLinkClient } from './mss-link-client';
|
|
2
|
+
import { WasmCryptoEngine } from '../core/wasm-crypto-engine';
|
|
3
|
+
import { MessagesCryptoClient } from '../modules/messages/messages-crypto.client';
|
|
4
|
+
import { StorageCryptoClient } from '../modules/storage/storage-crypto.client';
|
|
5
|
+
import { MediaCryptoClient } from '../modules/media/media-crypto.client';
|
|
6
|
+
export class BrowserMssLinkClient extends MssLinkClient {
|
|
7
|
+
cryptoEngine;
|
|
8
|
+
messagesCrypto;
|
|
9
|
+
storageCrypto;
|
|
10
|
+
mediaCrypto;
|
|
11
|
+
constructor(options) {
|
|
12
|
+
super(options);
|
|
13
|
+
this.cryptoEngine = new WasmCryptoEngine({
|
|
14
|
+
userId: options.userId,
|
|
15
|
+
apiBaseUrl: options.baseUrl,
|
|
16
|
+
accessToken: typeof options.token === 'string' ? options.token : undefined,
|
|
17
|
+
deviceId: options.deviceId,
|
|
18
|
+
registrationId: options.registrationId,
|
|
19
|
+
signedPrekeyId: options.signedPrekeyId,
|
|
20
|
+
initialOneTimePrekeyCount: options.initialOneTimePrekeyCount,
|
|
21
|
+
minOneTimePrekeys: options.minOneTimePrekeys,
|
|
22
|
+
replenishOneTimePrekeys: options.replenishOneTimePrekeys,
|
|
23
|
+
});
|
|
24
|
+
this.messagesCrypto = new MessagesCryptoClient(this.cryptoEngine);
|
|
25
|
+
this.storageCrypto = new StorageCryptoClient(this.cryptoEngine);
|
|
26
|
+
this.mediaCrypto = new MediaCryptoClient(this.cryptoEngine);
|
|
27
|
+
}
|
|
28
|
+
async setToken(token) {
|
|
29
|
+
await super.setToken(token);
|
|
30
|
+
this.cryptoEngine.setAccessToken(token);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export function createBrowserClient(options) {
|
|
34
|
+
return new BrowserMssLinkClient(options);
|
|
35
|
+
}
|
package/dist/client/index.d.ts
CHANGED
|
@@ -1,21 +1,4 @@
|
|
|
1
|
-
export * from './api-base-url';
|
|
2
1
|
export * from './client-options';
|
|
3
|
-
export * from './
|
|
4
|
-
export * from './
|
|
5
|
-
export * from './
|
|
6
|
-
export * from './drive-key-wrapping';
|
|
7
|
-
export * from './drive-key-wrapping.contracts';
|
|
8
|
-
export * from './drive-sharing';
|
|
9
|
-
export * from './drive-sharing.contracts';
|
|
10
|
-
export * from './local-crypto-health';
|
|
11
|
-
export * from './local-crypto-health.contracts';
|
|
12
|
-
export * from './media-crypto.contracts';
|
|
13
|
-
export * from './media-message.contracts';
|
|
14
|
-
export * from './media-message-metadata';
|
|
15
|
-
export * from './message.contracts';
|
|
16
|
-
export * from './message-decryption.contracts';
|
|
17
|
-
export * from './message-decryption-state';
|
|
18
|
-
export * from './message.mapper';
|
|
19
|
-
export * from './mss-link-browser-client';
|
|
20
|
-
export * from './storage-metadata-crypto';
|
|
21
|
-
export * from './storage-metadata-crypto.contracts';
|
|
2
|
+
export * from './mss-link-client';
|
|
3
|
+
export * from './browser-client';
|
|
4
|
+
export * from './wasm-client.types';
|
package/dist/client/index.js
CHANGED
|
@@ -1,21 +1,4 @@
|
|
|
1
|
-
export * from './api-base-url';
|
|
2
1
|
export * from './client-options';
|
|
3
|
-
export * from './
|
|
4
|
-
export * from './
|
|
5
|
-
export * from './
|
|
6
|
-
export * from './drive-key-wrapping';
|
|
7
|
-
export * from './drive-key-wrapping.contracts';
|
|
8
|
-
export * from './drive-sharing';
|
|
9
|
-
export * from './drive-sharing.contracts';
|
|
10
|
-
export * from './local-crypto-health';
|
|
11
|
-
export * from './local-crypto-health.contracts';
|
|
12
|
-
export * from './media-crypto.contracts';
|
|
13
|
-
export * from './media-message.contracts';
|
|
14
|
-
export * from './media-message-metadata';
|
|
15
|
-
export * from './message.contracts';
|
|
16
|
-
export * from './message-decryption.contracts';
|
|
17
|
-
export * from './message-decryption-state';
|
|
18
|
-
export * from './message.mapper';
|
|
19
|
-
export * from './mss-link-browser-client';
|
|
20
|
-
export * from './storage-metadata-crypto';
|
|
21
|
-
export * from './storage-metadata-crypto.contracts';
|
|
2
|
+
export * from './mss-link-client';
|
|
3
|
+
export * from './browser-client';
|
|
4
|
+
export * from './wasm-client.types';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { HttpClient, HttpClientOptions } from '../core/http-client';
|
|
2
|
+
import { ChatsClient } from '../modules/chats/chats.client';
|
|
3
|
+
import { MessagesClient } from '../modules/messages/messages.client';
|
|
4
|
+
export interface MssLinkClientOptions extends HttpClientOptions {
|
|
5
|
+
}
|
|
6
|
+
export declare class MssLinkClient {
|
|
7
|
+
readonly http: HttpClient;
|
|
8
|
+
readonly chats: ChatsClient;
|
|
9
|
+
readonly messages: MessagesClient;
|
|
10
|
+
constructor(options: MssLinkClientOptions);
|
|
11
|
+
setToken(token: string): Promise<void>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { HttpClient } from '../core/http-client';
|
|
2
|
+
import { ChatsClient } from '../modules/chats/chats.client';
|
|
3
|
+
import { MessagesClient } from '../modules/messages/messages.client';
|
|
4
|
+
export class MssLinkClient {
|
|
5
|
+
http;
|
|
6
|
+
chats;
|
|
7
|
+
messages;
|
|
8
|
+
constructor(options) {
|
|
9
|
+
this.http = new HttpClient(options);
|
|
10
|
+
// Initialize all modules
|
|
11
|
+
this.chats = new ChatsClient(this.http);
|
|
12
|
+
this.messages = new MessagesClient(this.http);
|
|
13
|
+
}
|
|
14
|
+
async setToken(token) {
|
|
15
|
+
await this.http.setToken(token);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { WasmMssClient } from '@msssystems/mss-crypto-wasm';
|
|
2
|
-
import type { WasmEncryptedMediaBytes } from '
|
|
2
|
+
import type { WasmEncryptedMediaBytes } from '../modules/media/media-crypto.contracts';
|
|
3
3
|
export interface MssLinkWasmClient extends WasmMssClient {
|
|
4
4
|
sendMediaMessage(chatId: string, targetUserId: string, metadataJson: string, mediaAssetIds: string[]): Promise<string>;
|
|
5
5
|
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import type { MediaMessageAttachmentInput, MediaMessageAttachmentMetadata } from '../modules/media/media-message.contracts';
|
|
2
|
+
import type { DecryptedMessage } from '../modules/messages/message.contracts';
|
|
3
|
+
export type MessageStatus = 'SENT' | 'DELIVERED' | 'READ';
|
|
4
|
+
export interface MessageReceiptSummary {
|
|
5
|
+
total: number;
|
|
6
|
+
sent: number;
|
|
7
|
+
delivered: number;
|
|
8
|
+
read: number;
|
|
9
|
+
}
|
|
10
|
+
export interface MessageMediaAttachment {
|
|
11
|
+
id: string;
|
|
12
|
+
assetId: string;
|
|
13
|
+
mimeType: string;
|
|
14
|
+
size: string;
|
|
15
|
+
status: 'ATTACHED';
|
|
16
|
+
uploadedAt: string;
|
|
17
|
+
}
|
|
18
|
+
export interface ChatMember {
|
|
19
|
+
id: string;
|
|
20
|
+
role: 'MEMBER' | 'ADMIN';
|
|
21
|
+
archivedAt?: string | null;
|
|
22
|
+
hiddenAt?: string | null;
|
|
23
|
+
lastReadAt?: string | null;
|
|
24
|
+
user: {
|
|
25
|
+
id: string;
|
|
26
|
+
username: string;
|
|
27
|
+
displayName: string;
|
|
28
|
+
avatarUrl?: string | null;
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
export interface Chat {
|
|
32
|
+
id: string;
|
|
33
|
+
type: 'DIRECT' | 'GROUP';
|
|
34
|
+
name?: string | null;
|
|
35
|
+
avatarUrl?: string | null;
|
|
36
|
+
members: ChatMember[];
|
|
37
|
+
messages?: Array<{
|
|
38
|
+
id: string;
|
|
39
|
+
ciphertext: string;
|
|
40
|
+
senderId: string;
|
|
41
|
+
createdAt: string;
|
|
42
|
+
}>;
|
|
43
|
+
myArchivedAt?: string | null;
|
|
44
|
+
myHiddenAt?: string | null;
|
|
45
|
+
myLastReadAt?: string | null;
|
|
46
|
+
createdAt: string;
|
|
47
|
+
updatedAt: string;
|
|
48
|
+
}
|
|
49
|
+
export interface Message {
|
|
50
|
+
id: string;
|
|
51
|
+
type: string;
|
|
52
|
+
status: MessageStatus;
|
|
53
|
+
myReceiptStatus?: MessageStatus | null;
|
|
54
|
+
receiptSummary: MessageReceiptSummary;
|
|
55
|
+
clientMessageId?: string | null;
|
|
56
|
+
ciphertext: string;
|
|
57
|
+
chatId: string;
|
|
58
|
+
senderId: string;
|
|
59
|
+
sender: {
|
|
60
|
+
id: string;
|
|
61
|
+
displayName: string;
|
|
62
|
+
avatarUrl?: string | null;
|
|
63
|
+
};
|
|
64
|
+
media: MessageMediaAttachment[];
|
|
65
|
+
createdAt: string;
|
|
66
|
+
updatedAt: string;
|
|
67
|
+
}
|
|
68
|
+
export interface CreateMediaUploadInput {
|
|
69
|
+
originalName: string;
|
|
70
|
+
mimeType: string;
|
|
71
|
+
size: number;
|
|
72
|
+
}
|
|
73
|
+
export interface MediaUploadInitResponse {
|
|
74
|
+
assetId: string;
|
|
75
|
+
uploadUrl: string;
|
|
76
|
+
metadata: Record<string, string>;
|
|
77
|
+
}
|
|
78
|
+
export interface MediaAssetUrlResponse {
|
|
79
|
+
assetId: string;
|
|
80
|
+
url: string;
|
|
81
|
+
}
|
|
82
|
+
export interface MediaAssetBlobResponse {
|
|
83
|
+
blob: Blob;
|
|
84
|
+
fileName: string;
|
|
85
|
+
}
|
|
86
|
+
export interface MessagesResponse {
|
|
87
|
+
messages: Message[];
|
|
88
|
+
nextCursor?: string | null;
|
|
89
|
+
}
|
|
90
|
+
export interface SyncCheckpoint {
|
|
91
|
+
lastAckedSequence: string;
|
|
92
|
+
acknowledgedAt: string;
|
|
93
|
+
}
|
|
94
|
+
export interface AckSyncInput {
|
|
95
|
+
sequence: string;
|
|
96
|
+
}
|
|
97
|
+
export interface MarkMessagesStatusInput {
|
|
98
|
+
chatId: string;
|
|
99
|
+
throughMessageId?: string;
|
|
100
|
+
limit?: number;
|
|
101
|
+
}
|
|
102
|
+
export type SyncEventType = 'MESSAGE_NEW' | 'MESSAGE_STATUS_UPDATED';
|
|
103
|
+
export interface SyncEvent {
|
|
104
|
+
sequence: string;
|
|
105
|
+
type: SyncEventType;
|
|
106
|
+
chatId: string;
|
|
107
|
+
messageId?: string | null;
|
|
108
|
+
messageStatus?: MessageStatus | null;
|
|
109
|
+
message?: Message | null;
|
|
110
|
+
createdAt: string;
|
|
111
|
+
}
|
|
112
|
+
export interface SyncEventsResponse {
|
|
113
|
+
events: SyncEvent[];
|
|
114
|
+
nextCursor?: string | null;
|
|
115
|
+
}
|
|
116
|
+
export interface SyncEventsInput {
|
|
117
|
+
cursor?: string | null;
|
|
118
|
+
limit?: number;
|
|
119
|
+
}
|
|
120
|
+
export interface SyncClientInput {
|
|
121
|
+
profileId: string;
|
|
122
|
+
accessToken: string;
|
|
123
|
+
}
|
|
124
|
+
export interface ChatMessagesPageInput {
|
|
125
|
+
chatId: string;
|
|
126
|
+
before?: string;
|
|
127
|
+
after?: string;
|
|
128
|
+
limit?: number;
|
|
129
|
+
}
|
|
130
|
+
export interface CreateDirectChatInput {
|
|
131
|
+
targetUserId: string;
|
|
132
|
+
}
|
|
133
|
+
export interface CreateGroupChatInput {
|
|
134
|
+
name: string;
|
|
135
|
+
memberUserIds: string[];
|
|
136
|
+
}
|
|
137
|
+
export interface DecryptedMessagesInput {
|
|
138
|
+
profileId: string;
|
|
139
|
+
accessToken: string;
|
|
140
|
+
chatId: string;
|
|
141
|
+
}
|
|
142
|
+
export interface SendEncryptedMessageInput {
|
|
143
|
+
profileId: string;
|
|
144
|
+
accessToken: string;
|
|
145
|
+
chatId: string;
|
|
146
|
+
targetUserId: string;
|
|
147
|
+
text: string;
|
|
148
|
+
}
|
|
149
|
+
export interface SendMediaMessageInput {
|
|
150
|
+
profileId: string;
|
|
151
|
+
accessToken: string;
|
|
152
|
+
chatId: string;
|
|
153
|
+
targetUserId: string;
|
|
154
|
+
attachments: MediaMessageAttachmentInput[];
|
|
155
|
+
caption?: string;
|
|
156
|
+
}
|
|
157
|
+
export interface EncryptMediaAssetInput {
|
|
158
|
+
profileId: string;
|
|
159
|
+
accessToken: string;
|
|
160
|
+
assetId: string;
|
|
161
|
+
file: Blob;
|
|
162
|
+
mimeType: string;
|
|
163
|
+
size: string | number;
|
|
164
|
+
originalName?: string;
|
|
165
|
+
uploadedAt?: string;
|
|
166
|
+
}
|
|
167
|
+
export interface DecryptMediaAssetInput {
|
|
168
|
+
profileId: string;
|
|
169
|
+
accessToken: string;
|
|
170
|
+
encryptedBlob: Blob;
|
|
171
|
+
metadata: MediaMessageAttachmentMetadata;
|
|
172
|
+
}
|
|
173
|
+
export interface UploadAndSendMediaMessageInput {
|
|
174
|
+
profileId: string;
|
|
175
|
+
accessToken: string;
|
|
176
|
+
chatId: string;
|
|
177
|
+
targetUserId: string;
|
|
178
|
+
file: File;
|
|
179
|
+
caption?: string;
|
|
180
|
+
onLifecycleChange?: (event: MediaUploadLifecycleEvent) => void;
|
|
181
|
+
}
|
|
182
|
+
export type MediaUploadLifecycleStatus = 'uploading' | 'uploaded' | 'attached' | 'failed';
|
|
183
|
+
export interface MediaUploadLifecycleEvent {
|
|
184
|
+
status: MediaUploadLifecycleStatus;
|
|
185
|
+
assetId?: string;
|
|
186
|
+
errorMessage?: string;
|
|
187
|
+
}
|
|
188
|
+
export type { DecryptedMessage };
|
|
189
|
+
export type { MediaMessageAttachmentMetadata };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export interface HttpClientOptions {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
token?: string | (() => string | Promise<string>);
|
|
4
|
+
fetch?: typeof fetch;
|
|
5
|
+
}
|
|
6
|
+
export declare class HttpClient {
|
|
7
|
+
private baseUrl;
|
|
8
|
+
private token?;
|
|
9
|
+
private customFetch;
|
|
10
|
+
constructor(options: HttpClientOptions);
|
|
11
|
+
setToken(token: string): Promise<void>;
|
|
12
|
+
private getHeaders;
|
|
13
|
+
request<T>(method: string, path: string, options?: {
|
|
14
|
+
body?: any;
|
|
15
|
+
params?: Record<string, any>;
|
|
16
|
+
headers?: Record<string, string>;
|
|
17
|
+
responseType?: 'json' | 'blob';
|
|
18
|
+
}): Promise<T>;
|
|
19
|
+
get<T>(path: string, options?: Omit<Parameters<typeof this.request>[2], 'body'>): Promise<T>;
|
|
20
|
+
post<T>(path: string, body?: any, options?: Omit<Parameters<typeof this.request>[2], 'body'>): Promise<T>;
|
|
21
|
+
put<T>(path: string, body?: any, options?: Omit<Parameters<typeof this.request>[2], 'body'>): Promise<T>;
|
|
22
|
+
patch<T>(path: string, body?: any, options?: Omit<Parameters<typeof this.request>[2], 'body'>): Promise<T>;
|
|
23
|
+
delete<T>(path: string, options?: Omit<Parameters<typeof this.request>[2], 'body'>): Promise<T>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { ApiError } from '../errors/api-error';
|
|
2
|
+
export class HttpClient {
|
|
3
|
+
baseUrl;
|
|
4
|
+
token;
|
|
5
|
+
customFetch;
|
|
6
|
+
constructor(options) {
|
|
7
|
+
this.baseUrl = options.baseUrl.replace(/\/$/, '');
|
|
8
|
+
this.token = options.token;
|
|
9
|
+
// Fallback to global fetch if not provided
|
|
10
|
+
this.customFetch = options.fetch ?? (typeof globalThis !== 'undefined' ? globalThis.fetch.bind(globalThis) : fetch);
|
|
11
|
+
}
|
|
12
|
+
async setToken(token) {
|
|
13
|
+
this.token = token;
|
|
14
|
+
}
|
|
15
|
+
async getHeaders(customHeaders) {
|
|
16
|
+
const headers = {
|
|
17
|
+
'Content-Type': 'application/json',
|
|
18
|
+
...customHeaders,
|
|
19
|
+
};
|
|
20
|
+
if (this.token) {
|
|
21
|
+
const tokenStr = typeof this.token === 'function' ? await this.token() : this.token;
|
|
22
|
+
if (tokenStr) {
|
|
23
|
+
headers['Authorization'] = `Bearer ${tokenStr}`;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return headers;
|
|
27
|
+
}
|
|
28
|
+
async request(method, path, options = {}) {
|
|
29
|
+
const url = new URL(`${this.baseUrl}${path}`);
|
|
30
|
+
if (options.params) {
|
|
31
|
+
for (const [key, value] of Object.entries(options.params)) {
|
|
32
|
+
if (value !== undefined && value !== null) {
|
|
33
|
+
url.searchParams.append(key, String(value));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const headers = await this.getHeaders(options.headers);
|
|
38
|
+
const fetchOptions = {
|
|
39
|
+
method,
|
|
40
|
+
headers,
|
|
41
|
+
};
|
|
42
|
+
if (options.body) {
|
|
43
|
+
fetchOptions.body = JSON.stringify(options.body);
|
|
44
|
+
}
|
|
45
|
+
const response = await this.customFetch(url.toString(), fetchOptions);
|
|
46
|
+
if (!response.ok) {
|
|
47
|
+
let errorPayload;
|
|
48
|
+
try {
|
|
49
|
+
errorPayload = await response.json();
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
errorPayload = { message: response.statusText };
|
|
53
|
+
}
|
|
54
|
+
throw new ApiError(response.status, errorPayload.message || 'API request failed', errorPayload);
|
|
55
|
+
}
|
|
56
|
+
if (options.responseType === 'blob') {
|
|
57
|
+
return response.blob();
|
|
58
|
+
}
|
|
59
|
+
// Handle empty responses
|
|
60
|
+
if (response.status === 204 || response.headers.get('content-length') === '0') {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
return response.json();
|
|
64
|
+
}
|
|
65
|
+
get(path, options) {
|
|
66
|
+
return this.request('GET', path, options);
|
|
67
|
+
}
|
|
68
|
+
post(path, body, options) {
|
|
69
|
+
return this.request('POST', path, { ...options, body });
|
|
70
|
+
}
|
|
71
|
+
put(path, body, options) {
|
|
72
|
+
return this.request('PUT', path, { ...options, body });
|
|
73
|
+
}
|
|
74
|
+
patch(path, body, options) {
|
|
75
|
+
return this.request('PATCH', path, { ...options, body });
|
|
76
|
+
}
|
|
77
|
+
delete(path, options) {
|
|
78
|
+
return this.request('DELETE', path, options);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { LocalCryptoErrorCode } from '
|
|
1
|
+
import type { LocalCryptoErrorCode } from '../errors/decryption-errors';
|
|
2
2
|
export type LocalCryptoHealthStatus = 'ready' | 'recovery_required' | 'corrupt' | 'unavailable';
|
|
3
3
|
export type LocalCryptoHealthErrorCode = LocalCryptoErrorCode;
|
|
4
4
|
export interface LocalCryptoHealth {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { WasmCallQueue } from './wasm-call-queue';
|
|
2
|
+
import type { MssCryptoWasmModule, WasmMssClientInstance } from '../client/wasm-client.types';
|
|
3
|
+
export interface WasmCryptoEngineOptions {
|
|
4
|
+
userId: string;
|
|
5
|
+
apiBaseUrl: string;
|
|
6
|
+
accessToken?: string | undefined;
|
|
7
|
+
deviceId?: number | undefined;
|
|
8
|
+
registrationId?: number | undefined;
|
|
9
|
+
signedPrekeyId?: number | undefined;
|
|
10
|
+
initialOneTimePrekeyCount?: number | undefined;
|
|
11
|
+
minOneTimePrekeys?: number | undefined;
|
|
12
|
+
replenishOneTimePrekeys?: number | undefined;
|
|
13
|
+
}
|
|
14
|
+
export declare class WasmCryptoEngine {
|
|
15
|
+
private readonly userId;
|
|
16
|
+
private readonly apiBaseUrl;
|
|
17
|
+
private readonly deviceId;
|
|
18
|
+
private readonly registrationId;
|
|
19
|
+
private readonly signedPrekeyId;
|
|
20
|
+
private readonly initialOneTimePrekeyCount;
|
|
21
|
+
private readonly minOneTimePrekeys;
|
|
22
|
+
private readonly replenishOneTimePrekeys;
|
|
23
|
+
readonly queue: WasmCallQueue;
|
|
24
|
+
private wasmClient;
|
|
25
|
+
private wasmModulePromise;
|
|
26
|
+
private accessToken;
|
|
27
|
+
constructor(options: WasmCryptoEngineOptions);
|
|
28
|
+
setAccessToken(accessToken: string | null): void;
|
|
29
|
+
ensureReady(): Promise<void>;
|
|
30
|
+
reset(): void;
|
|
31
|
+
runWithClient<T>(callback: (client: WasmMssClientInstance) => Promise<T>): Promise<T>;
|
|
32
|
+
getClient(): Promise<WasmMssClientInstance>;
|
|
33
|
+
loadWasmModule(): Promise<MssCryptoWasmModule>;
|
|
34
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { normalizeProductApiBaseUrl } from './api-base-url';
|
|
2
|
+
import { normalizeLocalCryptoError } from '../errors/decryption-errors';
|
|
3
|
+
import { WasmCallQueue } from './wasm-call-queue';
|
|
4
|
+
const DEFAULT_DEVICE_ID = 1;
|
|
5
|
+
const DEFAULT_REGISTRATION_ID = 1;
|
|
6
|
+
const DEFAULT_SIGNED_PREKEY_ID = 1;
|
|
7
|
+
const DEFAULT_ONE_TIME_PREKEY_COUNT = 10;
|
|
8
|
+
const DEFAULT_MIN_ONE_TIME_PREKEYS = 5;
|
|
9
|
+
const DEFAULT_REPLENISH_ONE_TIME_PREKEYS = 10;
|
|
10
|
+
export class WasmCryptoEngine {
|
|
11
|
+
userId;
|
|
12
|
+
apiBaseUrl;
|
|
13
|
+
deviceId;
|
|
14
|
+
registrationId;
|
|
15
|
+
signedPrekeyId;
|
|
16
|
+
initialOneTimePrekeyCount;
|
|
17
|
+
minOneTimePrekeys;
|
|
18
|
+
replenishOneTimePrekeys;
|
|
19
|
+
queue = new WasmCallQueue();
|
|
20
|
+
wasmClient = null;
|
|
21
|
+
wasmModulePromise = null;
|
|
22
|
+
accessToken;
|
|
23
|
+
constructor(options) {
|
|
24
|
+
this.userId = options.userId;
|
|
25
|
+
this.apiBaseUrl = normalizeProductApiBaseUrl(options.apiBaseUrl);
|
|
26
|
+
this.accessToken = options.accessToken ?? null;
|
|
27
|
+
this.deviceId = options.deviceId ?? DEFAULT_DEVICE_ID;
|
|
28
|
+
this.registrationId = options.registrationId ?? DEFAULT_REGISTRATION_ID;
|
|
29
|
+
this.signedPrekeyId = options.signedPrekeyId ?? DEFAULT_SIGNED_PREKEY_ID;
|
|
30
|
+
this.initialOneTimePrekeyCount =
|
|
31
|
+
options.initialOneTimePrekeyCount ?? DEFAULT_ONE_TIME_PREKEY_COUNT;
|
|
32
|
+
this.minOneTimePrekeys =
|
|
33
|
+
options.minOneTimePrekeys ?? DEFAULT_MIN_ONE_TIME_PREKEYS;
|
|
34
|
+
this.replenishOneTimePrekeys =
|
|
35
|
+
options.replenishOneTimePrekeys ?? DEFAULT_REPLENISH_ONE_TIME_PREKEYS;
|
|
36
|
+
}
|
|
37
|
+
setAccessToken(accessToken) {
|
|
38
|
+
this.accessToken = accessToken;
|
|
39
|
+
this.wasmClient?.setAccessToken(accessToken);
|
|
40
|
+
}
|
|
41
|
+
async ensureReady() {
|
|
42
|
+
try {
|
|
43
|
+
await this.runWithClient(async (client) => {
|
|
44
|
+
await client.ensureDeviceRegistered(this.registrationId, this.signedPrekeyId, this.initialOneTimePrekeyCount);
|
|
45
|
+
await client.replenishOneTimePreKeys(this.minOneTimePrekeys, this.replenishOneTimePrekeys);
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
throw normalizeLocalCryptoError(error);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
reset() {
|
|
53
|
+
this.wasmClient?.free();
|
|
54
|
+
this.wasmClient = null;
|
|
55
|
+
this.wasmModulePromise = null;
|
|
56
|
+
}
|
|
57
|
+
async runWithClient(callback) {
|
|
58
|
+
return this.queue.run(async () => callback(await this.getClient()));
|
|
59
|
+
}
|
|
60
|
+
async getClient() {
|
|
61
|
+
if (typeof window === 'undefined') {
|
|
62
|
+
throw new Error('MSS Link browser client is available only in browser context.');
|
|
63
|
+
}
|
|
64
|
+
if (!this.wasmClient) {
|
|
65
|
+
const sdkModule = await this.loadWasmModule();
|
|
66
|
+
this.wasmClient = new sdkModule.WasmMssClient(this.userId, this.deviceId, this.apiBaseUrl);
|
|
67
|
+
this.wasmClient.setAccessToken(this.accessToken);
|
|
68
|
+
}
|
|
69
|
+
return this.wasmClient;
|
|
70
|
+
}
|
|
71
|
+
loadWasmModule() {
|
|
72
|
+
this.wasmModulePromise ??= import('@msssystems/mss-crypto-wasm').then((module) => module);
|
|
73
|
+
return this.wasmModulePromise;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SdkError } from './sdk-error';
|
|
2
|
+
export class ApiError extends SdkError {
|
|
3
|
+
status;
|
|
4
|
+
payload;
|
|
5
|
+
constructor(status, message, payload) {
|
|
6
|
+
super(`[HTTP ${status}] ${message}`);
|
|
7
|
+
this.status = status;
|
|
8
|
+
this.payload = payload;
|
|
9
|
+
this.name = 'ApiError';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { HttpClient } from '../../core/http-client';
|
|
2
|
+
export declare class ChatsClient {
|
|
3
|
+
private readonly http;
|
|
4
|
+
constructor(http: HttpClient);
|
|
5
|
+
list(): Promise<any[]>;
|
|
6
|
+
getDetails(chatId: string): Promise<any>;
|
|
7
|
+
createDirect(targetUserId: string): Promise<any>;
|
|
8
|
+
createGroup(name: string, userIds: string[]): Promise<any>;
|
|
9
|
+
archive(chatId: string): Promise<any>;
|
|
10
|
+
hide(chatId: string): Promise<any>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// TODO: Import proper types from contracts
|
|
2
|
+
export class ChatsClient {
|
|
3
|
+
http;
|
|
4
|
+
constructor(http) {
|
|
5
|
+
this.http = http;
|
|
6
|
+
}
|
|
7
|
+
async list() {
|
|
8
|
+
return this.http.get('/link/v1/chats');
|
|
9
|
+
}
|
|
10
|
+
async getDetails(chatId) {
|
|
11
|
+
return this.http.get(`/link/v1/chats/${chatId}`);
|
|
12
|
+
}
|
|
13
|
+
async createDirect(targetUserId) {
|
|
14
|
+
return this.http.post('/link/v1/chats/direct', { targetUserId });
|
|
15
|
+
}
|
|
16
|
+
async createGroup(name, userIds) {
|
|
17
|
+
return this.http.post('/link/v1/chats/group', { name, userIds });
|
|
18
|
+
}
|
|
19
|
+
async archive(chatId) {
|
|
20
|
+
return this.http.post(`/link/v1/chats/${chatId}/archive`);
|
|
21
|
+
}
|
|
22
|
+
async hide(chatId) {
|
|
23
|
+
return this.http.post(`/link/v1/chats/${chatId}/hide`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { WasmCryptoEngine } from '../../core/wasm-crypto-engine';
|
|
2
|
+
import type { DecryptMediaBlobInput, DecryptedMediaBlobResult, EncryptedMediaBlobResult, EncryptMediaBlobInput } from './media-crypto.contracts';
|
|
3
|
+
import type { SendMediaMessageParams } from './media-message.contracts';
|
|
4
|
+
export declare class MediaCryptoClient {
|
|
5
|
+
private readonly engine;
|
|
6
|
+
constructor(engine: WasmCryptoEngine);
|
|
7
|
+
sendMediaMessage(params: SendMediaMessageParams): Promise<string>;
|
|
8
|
+
encryptMediaBlob(input: EncryptMediaBlobInput): Promise<EncryptedMediaBlobResult>;
|
|
9
|
+
decryptMediaBlob(input: DecryptMediaBlobInput): Promise<DecryptedMediaBlobResult>;
|
|
10
|
+
}
|