@msssystems/mss-link-sdk 0.1.0 → 0.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.
- package/dist/client/api-base-url.d.ts +1 -0
- package/dist/client/api-base-url.js +10 -0
- package/dist/client/client-options.d.ts +11 -0
- package/dist/client/client-options.js +1 -0
- package/dist/client/decryption-errors.d.ts +7 -0
- package/dist/client/decryption-errors.js +36 -0
- package/dist/client/index.d.ts +10 -0
- package/dist/client/index.js +10 -0
- package/dist/client/local-crypto-health.contracts.d.ts +9 -0
- package/dist/client/local-crypto-health.contracts.js +1 -0
- package/dist/client/local-crypto-health.d.ts +2 -0
- package/dist/client/local-crypto-health.js +29 -0
- package/dist/client/message-decryption-state.d.ts +2 -0
- package/dist/client/message-decryption-state.js +81 -0
- package/dist/client/message-decryption.contracts.d.ts +24 -0
- package/dist/client/message-decryption.contracts.js +1 -0
- package/dist/client/message.contracts.d.ts +20 -0
- package/dist/client/message.contracts.js +1 -0
- package/dist/client/message.mapper.d.ts +2 -0
- package/dist/client/message.mapper.js +14 -0
- package/dist/client/mss-link-browser-client.d.ts +33 -0
- package/dist/client/mss-link-browser-client.js +110 -0
- package/dist/client/wasm-call-queue.d.ts +4 -0
- package/dist/client/wasm-call-queue.js +8 -0
- package/dist/client/wasm-client.types.d.ts +6 -0
- package/dist/client/wasm-client.types.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +10 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function normalizeProductApiBaseUrl(apiBaseUrl: string): string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function normalizeProductApiBaseUrl(apiBaseUrl) {
|
|
2
|
+
const normalizedApiUrl = apiBaseUrl.replace(/\/+$/, '');
|
|
3
|
+
if (!normalizedApiUrl) {
|
|
4
|
+
return '/link/v1';
|
|
5
|
+
}
|
|
6
|
+
if (normalizedApiUrl.endsWith('/link/v1')) {
|
|
7
|
+
return normalizedApiUrl;
|
|
8
|
+
}
|
|
9
|
+
return `${normalizedApiUrl}/link/v1`;
|
|
10
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface MssLinkBrowserClientOptions {
|
|
2
|
+
userId: string;
|
|
3
|
+
apiBaseUrl: string;
|
|
4
|
+
accessToken?: string | null;
|
|
5
|
+
deviceId?: number;
|
|
6
|
+
registrationId?: number;
|
|
7
|
+
signedPrekeyId?: number;
|
|
8
|
+
initialOneTimePrekeyCount?: number;
|
|
9
|
+
minOneTimePrekeys?: number;
|
|
10
|
+
replenishOneTimePrekeys?: number;
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type LocalCryptoErrorCode = 'corrupt_session' | 'missing_local_session' | 'unsupported_envelope' | 'local_crypto_unavailable' | 'unknown';
|
|
2
|
+
export declare class LocalCryptoError extends Error {
|
|
3
|
+
readonly code: LocalCryptoErrorCode;
|
|
4
|
+
readonly cause?: unknown;
|
|
5
|
+
constructor(code: LocalCryptoErrorCode, message: string, cause?: unknown);
|
|
6
|
+
}
|
|
7
|
+
export declare function normalizeLocalCryptoError(error: unknown): LocalCryptoError;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export class LocalCryptoError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
cause;
|
|
4
|
+
constructor(code, message, cause) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = 'LocalCryptoError';
|
|
7
|
+
this.code = code;
|
|
8
|
+
this.cause = cause;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function normalizeLocalCryptoError(error) {
|
|
12
|
+
if (error instanceof LocalCryptoError) {
|
|
13
|
+
return error;
|
|
14
|
+
}
|
|
15
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
16
|
+
const normalizedMessage = message.toLowerCase();
|
|
17
|
+
if (normalizedMessage.includes('corrupt') ||
|
|
18
|
+
normalizedMessage.includes('ratchet')) {
|
|
19
|
+
return new LocalCryptoError('corrupt_session', message, error);
|
|
20
|
+
}
|
|
21
|
+
if (normalizedMessage.includes('missing') ||
|
|
22
|
+
normalizedMessage.includes('not found') ||
|
|
23
|
+
normalizedMessage.includes('session')) {
|
|
24
|
+
return new LocalCryptoError('missing_local_session', message, error);
|
|
25
|
+
}
|
|
26
|
+
if (normalizedMessage.includes('unsupported') ||
|
|
27
|
+
normalizedMessage.includes('envelope')) {
|
|
28
|
+
return new LocalCryptoError('unsupported_envelope', message, error);
|
|
29
|
+
}
|
|
30
|
+
if (normalizedMessage.includes('indexeddb') ||
|
|
31
|
+
normalizedMessage.includes('wasm') ||
|
|
32
|
+
normalizedMessage.includes('browser')) {
|
|
33
|
+
return new LocalCryptoError('local_crypto_unavailable', message, error);
|
|
34
|
+
}
|
|
35
|
+
return new LocalCryptoError('unknown', message, error);
|
|
36
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './api-base-url';
|
|
2
|
+
export * from './client-options';
|
|
3
|
+
export * from './decryption-errors';
|
|
4
|
+
export * from './local-crypto-health';
|
|
5
|
+
export * from './local-crypto-health.contracts';
|
|
6
|
+
export * from './message.contracts';
|
|
7
|
+
export * from './message-decryption.contracts';
|
|
8
|
+
export * from './message-decryption-state';
|
|
9
|
+
export * from './message.mapper';
|
|
10
|
+
export * from './mss-link-browser-client';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export * from './api-base-url';
|
|
2
|
+
export * from './client-options';
|
|
3
|
+
export * from './decryption-errors';
|
|
4
|
+
export * from './local-crypto-health';
|
|
5
|
+
export * from './local-crypto-health.contracts';
|
|
6
|
+
export * from './message.contracts';
|
|
7
|
+
export * from './message-decryption.contracts';
|
|
8
|
+
export * from './message-decryption-state';
|
|
9
|
+
export * from './message.mapper';
|
|
10
|
+
export * from './mss-link-browser-client';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { LocalCryptoErrorCode } from './decryption-errors';
|
|
2
|
+
export type LocalCryptoHealthStatus = 'ready' | 'recovery_required' | 'corrupt' | 'unavailable';
|
|
3
|
+
export type LocalCryptoHealthErrorCode = LocalCryptoErrorCode;
|
|
4
|
+
export interface LocalCryptoHealth {
|
|
5
|
+
ready: boolean;
|
|
6
|
+
status: LocalCryptoHealthStatus;
|
|
7
|
+
errorCode?: LocalCryptoHealthErrorCode;
|
|
8
|
+
checkedAt: string;
|
|
9
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { normalizeLocalCryptoError } from './decryption-errors';
|
|
2
|
+
export async function checkLocalCryptoHealth(checkReady) {
|
|
3
|
+
try {
|
|
4
|
+
await checkReady();
|
|
5
|
+
return {
|
|
6
|
+
ready: true,
|
|
7
|
+
status: 'ready',
|
|
8
|
+
checkedAt: new Date().toISOString(),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
const normalizedError = normalizeLocalCryptoError(error);
|
|
13
|
+
return {
|
|
14
|
+
ready: false,
|
|
15
|
+
status: getLocalCryptoHealthStatus(normalizedError.code),
|
|
16
|
+
errorCode: normalizedError.code,
|
|
17
|
+
checkedAt: new Date().toISOString(),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function getLocalCryptoHealthStatus(errorCode) {
|
|
22
|
+
if (errorCode === 'corrupt_session') {
|
|
23
|
+
return 'corrupt';
|
|
24
|
+
}
|
|
25
|
+
if (errorCode === 'local_crypto_unavailable') {
|
|
26
|
+
return 'unavailable';
|
|
27
|
+
}
|
|
28
|
+
return 'recovery_required';
|
|
29
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import type { CreateMessageDecryptionStateIndexInput, EncryptedMessageRef, MessageDecryptStateIndex } from './message-decryption.contracts';
|
|
2
|
+
export declare function createMessageDecryptionStateIndex<TMessage extends EncryptedMessageRef>({ messages, decryptedMessages, isDecrypting, decryptError, }: CreateMessageDecryptionStateIndexInput<TMessage>): MessageDecryptStateIndex;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { normalizeLocalCryptoError } from './decryption-errors';
|
|
2
|
+
export function createMessageDecryptionStateIndex({ messages, decryptedMessages, isDecrypting, decryptError, }) {
|
|
3
|
+
const decryptedById = createDecryptedMessageIndex(decryptedMessages);
|
|
4
|
+
const index = new Map();
|
|
5
|
+
for (const message of messages) {
|
|
6
|
+
const decrypted = findDecryptedMessage(decryptedById, message);
|
|
7
|
+
const state = createMessageDecryptState({
|
|
8
|
+
message,
|
|
9
|
+
decrypted,
|
|
10
|
+
isDecrypting,
|
|
11
|
+
decryptError,
|
|
12
|
+
});
|
|
13
|
+
index.set(message.id, state);
|
|
14
|
+
if (message.clientMessageId) {
|
|
15
|
+
index.set(message.clientMessageId, state);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return index;
|
|
19
|
+
}
|
|
20
|
+
function createMessageDecryptState({ message, decrypted, isDecrypting, decryptError, }) {
|
|
21
|
+
const baseState = createBaseMessageDecryptState(message);
|
|
22
|
+
if (decrypted?.text) {
|
|
23
|
+
return {
|
|
24
|
+
...baseState,
|
|
25
|
+
status: 'decrypted',
|
|
26
|
+
text: decrypted.text,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
if (isDecrypting) {
|
|
30
|
+
return {
|
|
31
|
+
...baseState,
|
|
32
|
+
status: 'pending',
|
|
33
|
+
reason: 'local_sync_in_progress',
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
if (decryptError) {
|
|
37
|
+
return {
|
|
38
|
+
...baseState,
|
|
39
|
+
status: 'failed',
|
|
40
|
+
reason: 'local_crypto_error',
|
|
41
|
+
errorCode: getDecryptErrorCode(decryptError),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
...baseState,
|
|
46
|
+
status: 'recovery_required',
|
|
47
|
+
reason: 'local_message_missing',
|
|
48
|
+
errorCode: 'missing_local_session',
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function createBaseMessageDecryptState(message) {
|
|
52
|
+
if (message.clientMessageId) {
|
|
53
|
+
return {
|
|
54
|
+
messageId: message.id,
|
|
55
|
+
clientMessageId: message.clientMessageId,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
messageId: message.id,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function createDecryptedMessageIndex(messages) {
|
|
63
|
+
const index = new Map();
|
|
64
|
+
for (const message of messages) {
|
|
65
|
+
index.set(message.id, message);
|
|
66
|
+
}
|
|
67
|
+
return index;
|
|
68
|
+
}
|
|
69
|
+
function findDecryptedMessage(index, message) {
|
|
70
|
+
const byMessageId = index.get(message.id);
|
|
71
|
+
if (byMessageId) {
|
|
72
|
+
return byMessageId;
|
|
73
|
+
}
|
|
74
|
+
if (message.clientMessageId) {
|
|
75
|
+
return index.get(message.clientMessageId);
|
|
76
|
+
}
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
function getDecryptErrorCode(error) {
|
|
80
|
+
return normalizeLocalCryptoError(error).code;
|
|
81
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { LocalCryptoErrorCode } from './decryption-errors';
|
|
2
|
+
import type { DecryptedMessage } from './message.contracts';
|
|
3
|
+
export type MessageDecryptStatus = 'decrypted' | 'pending' | 'failed' | 'recovery_required';
|
|
4
|
+
export type MessageDecryptReason = 'local_sync_in_progress' | 'local_message_missing' | 'local_crypto_error';
|
|
5
|
+
export type MessageDecryptErrorCode = LocalCryptoErrorCode;
|
|
6
|
+
export interface EncryptedMessageRef {
|
|
7
|
+
id: string;
|
|
8
|
+
clientMessageId?: string | null;
|
|
9
|
+
}
|
|
10
|
+
export interface MessageDecryptState {
|
|
11
|
+
messageId: string;
|
|
12
|
+
clientMessageId?: string | null;
|
|
13
|
+
status: MessageDecryptStatus;
|
|
14
|
+
reason?: MessageDecryptReason;
|
|
15
|
+
errorCode?: MessageDecryptErrorCode;
|
|
16
|
+
text?: string;
|
|
17
|
+
}
|
|
18
|
+
export type MessageDecryptStateIndex = Map<string, MessageDecryptState>;
|
|
19
|
+
export interface CreateMessageDecryptionStateIndexInput<TMessage extends EncryptedMessageRef = EncryptedMessageRef> {
|
|
20
|
+
messages: TMessage[];
|
|
21
|
+
decryptedMessages: DecryptedMessage[];
|
|
22
|
+
isDecrypting: boolean;
|
|
23
|
+
decryptError: unknown;
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface LocalSdkMessage {
|
|
2
|
+
messageId: string;
|
|
3
|
+
chatId: string;
|
|
4
|
+
senderId: string;
|
|
5
|
+
plaintext: string;
|
|
6
|
+
kind: string;
|
|
7
|
+
deliveryState: string;
|
|
8
|
+
createdAt?: string;
|
|
9
|
+
updatedAt?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface DecryptedMessage {
|
|
12
|
+
id: string;
|
|
13
|
+
chatId: string;
|
|
14
|
+
senderId: string;
|
|
15
|
+
text: string;
|
|
16
|
+
kind: string;
|
|
17
|
+
status: string;
|
|
18
|
+
createdAt: string;
|
|
19
|
+
updatedAt: string;
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export function mapLocalSdkMessage(message, now = () => new Date().toISOString()) {
|
|
2
|
+
const createdAt = message.createdAt ?? now();
|
|
3
|
+
const updatedAt = message.updatedAt ?? createdAt;
|
|
4
|
+
return {
|
|
5
|
+
id: message.messageId,
|
|
6
|
+
chatId: message.chatId,
|
|
7
|
+
senderId: message.senderId,
|
|
8
|
+
text: message.plaintext,
|
|
9
|
+
kind: message.kind,
|
|
10
|
+
status: message.deliveryState,
|
|
11
|
+
createdAt,
|
|
12
|
+
updatedAt,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { MssLinkBrowserClientOptions } from './client-options';
|
|
2
|
+
import type { LocalCryptoHealth } from './local-crypto-health.contracts';
|
|
3
|
+
import type { DecryptedMessage } from './message.contracts';
|
|
4
|
+
export declare class MssLinkBrowserClient {
|
|
5
|
+
private readonly userId;
|
|
6
|
+
private readonly apiBaseUrl;
|
|
7
|
+
private readonly deviceId;
|
|
8
|
+
private readonly registrationId;
|
|
9
|
+
private readonly signedPrekeyId;
|
|
10
|
+
private readonly initialOneTimePrekeyCount;
|
|
11
|
+
private readonly minOneTimePrekeys;
|
|
12
|
+
private readonly replenishOneTimePrekeys;
|
|
13
|
+
private readonly queue;
|
|
14
|
+
private wasmClient;
|
|
15
|
+
private wasmModulePromise;
|
|
16
|
+
private accessToken;
|
|
17
|
+
constructor(options: MssLinkBrowserClientOptions);
|
|
18
|
+
setAccessToken(accessToken: string | null): void;
|
|
19
|
+
ensureReady(): Promise<void>;
|
|
20
|
+
getLocalCryptoHealth(): Promise<LocalCryptoHealth>;
|
|
21
|
+
sendMessage(params: {
|
|
22
|
+
chatId: string;
|
|
23
|
+
targetUserId: string;
|
|
24
|
+
text: string;
|
|
25
|
+
kind?: string;
|
|
26
|
+
}): Promise<string>;
|
|
27
|
+
syncMessages(): Promise<void>;
|
|
28
|
+
getLocalMessages(chatId: string): Promise<DecryptedMessage[]>;
|
|
29
|
+
reset(): void;
|
|
30
|
+
private runWithClient;
|
|
31
|
+
private getClient;
|
|
32
|
+
private loadWasmModule;
|
|
33
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { normalizeProductApiBaseUrl } from './api-base-url';
|
|
2
|
+
import { normalizeLocalCryptoError } from './decryption-errors';
|
|
3
|
+
import { checkLocalCryptoHealth } from './local-crypto-health';
|
|
4
|
+
import { mapLocalSdkMessage } from './message.mapper';
|
|
5
|
+
import { WasmCallQueue } from './wasm-call-queue';
|
|
6
|
+
const DEFAULT_DEVICE_ID = 1;
|
|
7
|
+
const DEFAULT_REGISTRATION_ID = 1;
|
|
8
|
+
const DEFAULT_SIGNED_PREKEY_ID = 1;
|
|
9
|
+
const DEFAULT_ONE_TIME_PREKEY_COUNT = 10;
|
|
10
|
+
const DEFAULT_MIN_ONE_TIME_PREKEYS = 5;
|
|
11
|
+
const DEFAULT_REPLENISH_ONE_TIME_PREKEYS = 10;
|
|
12
|
+
export class MssLinkBrowserClient {
|
|
13
|
+
userId;
|
|
14
|
+
apiBaseUrl;
|
|
15
|
+
deviceId;
|
|
16
|
+
registrationId;
|
|
17
|
+
signedPrekeyId;
|
|
18
|
+
initialOneTimePrekeyCount;
|
|
19
|
+
minOneTimePrekeys;
|
|
20
|
+
replenishOneTimePrekeys;
|
|
21
|
+
queue = new WasmCallQueue();
|
|
22
|
+
wasmClient = null;
|
|
23
|
+
wasmModulePromise = null;
|
|
24
|
+
accessToken;
|
|
25
|
+
constructor(options) {
|
|
26
|
+
this.userId = options.userId;
|
|
27
|
+
this.apiBaseUrl = normalizeProductApiBaseUrl(options.apiBaseUrl);
|
|
28
|
+
this.accessToken = options.accessToken ?? null;
|
|
29
|
+
this.deviceId = options.deviceId ?? DEFAULT_DEVICE_ID;
|
|
30
|
+
this.registrationId =
|
|
31
|
+
options.registrationId ?? DEFAULT_REGISTRATION_ID;
|
|
32
|
+
this.signedPrekeyId =
|
|
33
|
+
options.signedPrekeyId ?? DEFAULT_SIGNED_PREKEY_ID;
|
|
34
|
+
this.initialOneTimePrekeyCount =
|
|
35
|
+
options.initialOneTimePrekeyCount ??
|
|
36
|
+
DEFAULT_ONE_TIME_PREKEY_COUNT;
|
|
37
|
+
this.minOneTimePrekeys =
|
|
38
|
+
options.minOneTimePrekeys ?? DEFAULT_MIN_ONE_TIME_PREKEYS;
|
|
39
|
+
this.replenishOneTimePrekeys =
|
|
40
|
+
options.replenishOneTimePrekeys ??
|
|
41
|
+
DEFAULT_REPLENISH_ONE_TIME_PREKEYS;
|
|
42
|
+
}
|
|
43
|
+
setAccessToken(accessToken) {
|
|
44
|
+
this.accessToken = accessToken;
|
|
45
|
+
this.wasmClient?.setAccessToken(accessToken);
|
|
46
|
+
}
|
|
47
|
+
async ensureReady() {
|
|
48
|
+
try {
|
|
49
|
+
await this.runWithClient(async (client) => {
|
|
50
|
+
await client.ensureDeviceRegistered(this.registrationId, this.signedPrekeyId, this.initialOneTimePrekeyCount);
|
|
51
|
+
await client.replenishOneTimePreKeys(this.minOneTimePrekeys, this.replenishOneTimePrekeys);
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
throw normalizeLocalCryptoError(error);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async getLocalCryptoHealth() {
|
|
59
|
+
return checkLocalCryptoHealth(() => this.ensureReady());
|
|
60
|
+
}
|
|
61
|
+
async sendMessage(params) {
|
|
62
|
+
try {
|
|
63
|
+
await this.ensureReady();
|
|
64
|
+
return this.runWithClient((client) => client.sendMessage(params.chatId, params.targetUserId, params.text, params.kind ?? 'TEXT'));
|
|
65
|
+
}
|
|
66
|
+
catch (error) {
|
|
67
|
+
throw normalizeLocalCryptoError(error);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async syncMessages() {
|
|
71
|
+
try {
|
|
72
|
+
await this.runWithClient((client) => client.syncMessages());
|
|
73
|
+
}
|
|
74
|
+
catch (error) {
|
|
75
|
+
throw normalizeLocalCryptoError(error);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async getLocalMessages(chatId) {
|
|
79
|
+
try {
|
|
80
|
+
const rawMessages = await this.runWithClient((client) => client.getLocalMessages(chatId));
|
|
81
|
+
return rawMessages.map((message) => mapLocalSdkMessage(message));
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
throw normalizeLocalCryptoError(error);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
reset() {
|
|
88
|
+
this.wasmClient?.free();
|
|
89
|
+
this.wasmClient = null;
|
|
90
|
+
this.wasmModulePromise = null;
|
|
91
|
+
}
|
|
92
|
+
async runWithClient(callback) {
|
|
93
|
+
return this.queue.run(async () => callback(await this.getClient()));
|
|
94
|
+
}
|
|
95
|
+
async getClient() {
|
|
96
|
+
if (typeof window === 'undefined') {
|
|
97
|
+
throw new Error('MSS Link browser client is available only in browser context.');
|
|
98
|
+
}
|
|
99
|
+
if (!this.wasmClient) {
|
|
100
|
+
const sdkModule = await this.loadWasmModule();
|
|
101
|
+
this.wasmClient = new sdkModule.WasmMssClient(this.userId, this.deviceId, this.apiBaseUrl);
|
|
102
|
+
this.wasmClient.setAccessToken(this.accessToken);
|
|
103
|
+
}
|
|
104
|
+
return this.wasmClient;
|
|
105
|
+
}
|
|
106
|
+
loadWasmModule() {
|
|
107
|
+
this.wasmModulePromise ??= import('@msssystems/mss-crypto-wasm');
|
|
108
|
+
return this.wasmModulePromise;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { WasmMssClient } from '@msssystems/mss-crypto-wasm';
|
|
2
|
+
export type WasmMssClientConstructor = new (userId: string, deviceId: number, apiBaseUrl: string) => WasmMssClient;
|
|
3
|
+
export interface MssCryptoWasmModule {
|
|
4
|
+
WasmMssClient: WasmMssClientConstructor;
|
|
5
|
+
}
|
|
6
|
+
export type WasmMssClientInstance = WasmMssClient;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@msssystems/mss-link-sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Official managed application SDK for MSS ecosystem",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -10,6 +10,10 @@
|
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
11
11
|
"import": "./dist/index.js"
|
|
12
12
|
},
|
|
13
|
+
"./client": {
|
|
14
|
+
"types": "./dist/client/index.d.ts",
|
|
15
|
+
"import": "./dist/client/index.js"
|
|
16
|
+
},
|
|
13
17
|
"./control": {
|
|
14
18
|
"types": "./dist/control/index.d.ts",
|
|
15
19
|
"import": "./dist/control/index.js"
|
|
@@ -49,12 +53,16 @@
|
|
|
49
53
|
"registry": "https://registry.npmjs.org/"
|
|
50
54
|
},
|
|
51
55
|
"peerDependencies": {
|
|
56
|
+
"@msssystems/mss-crypto-wasm": "^0.1.16",
|
|
52
57
|
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
|
53
58
|
"@nestjs/core": "^10.0.0 || ^11.0.0",
|
|
54
59
|
"express": "^4.0.0 || ^5.0.0",
|
|
55
60
|
"rxjs": "^7.0.0"
|
|
56
61
|
},
|
|
57
62
|
"peerDependenciesMeta": {
|
|
63
|
+
"@msssystems/mss-crypto-wasm": {
|
|
64
|
+
"optional": true
|
|
65
|
+
},
|
|
58
66
|
"@nestjs/common": {
|
|
59
67
|
"optional": true
|
|
60
68
|
},
|
|
@@ -69,6 +77,7 @@
|
|
|
69
77
|
}
|
|
70
78
|
},
|
|
71
79
|
"devDependencies": {
|
|
80
|
+
"@msssystems/mss-crypto-wasm": "^0.1.16",
|
|
72
81
|
"@nestjs/common": "^11.0.1",
|
|
73
82
|
"@nestjs/core": "^11.0.1",
|
|
74
83
|
"@types/express": "^5.0.0",
|