@msssystems/mss-link-sdk 0.2.1 → 0.2.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.
@@ -1,12 +1,14 @@
1
1
  export interface HttpClientOptions {
2
2
  baseUrl: string;
3
- token?: string | (() => string | Promise<string>);
3
+ token?: string | (() => string | Promise<string>) | undefined;
4
4
  fetch?: typeof fetch;
5
+ onUnauthorized?: (() => Promise<void>) | undefined;
5
6
  }
6
7
  export declare class HttpClient {
7
8
  private baseUrl;
8
9
  private token?;
9
10
  private customFetch;
11
+ private onUnauthorized?;
10
12
  constructor(options: HttpClientOptions);
11
13
  setToken(token: string): Promise<void>;
12
14
  private getHeaders;
@@ -3,9 +3,11 @@ export class HttpClient {
3
3
  baseUrl;
4
4
  token;
5
5
  customFetch;
6
+ onUnauthorized;
6
7
  constructor(options) {
7
8
  this.baseUrl = options.baseUrl.replace(/\/$/, '');
8
9
  this.token = options.token;
10
+ this.onUnauthorized = options.onUnauthorized;
9
11
  // Fallback to global fetch if not provided
10
12
  this.customFetch = options.fetch ?? (typeof globalThis !== 'undefined' ? globalThis.fetch.bind(globalThis) : fetch);
11
13
  }
@@ -42,7 +44,18 @@ export class HttpClient {
42
44
  if (options.body) {
43
45
  fetchOptions.body = JSON.stringify(options.body);
44
46
  }
45
- const response = await this.customFetch(url.toString(), fetchOptions);
47
+ let response = await this.customFetch(url.toString(), fetchOptions);
48
+ if (response.status === 401 && this.onUnauthorized) {
49
+ try {
50
+ await this.onUnauthorized();
51
+ // Update headers with new token
52
+ fetchOptions.headers = await this.getHeaders(options.headers);
53
+ response = await this.customFetch(url.toString(), fetchOptions);
54
+ }
55
+ catch (refreshError) {
56
+ // If refresh fails, let the original 401 error throw below
57
+ }
58
+ }
46
59
  if (!response.ok) {
47
60
  let errorPayload;
48
61
  try {
@@ -26,6 +26,7 @@ export declare class WasmCryptoEngine {
26
26
  private accessToken;
27
27
  constructor(options: WasmCryptoEngineOptions);
28
28
  setAccessToken(accessToken: string | null): void;
29
+ getLocalCryptoHealth(): Promise<import("./local-crypto-health.contracts").LocalCryptoHealth>;
29
30
  ensureReady(): Promise<void>;
30
31
  reset(): void;
31
32
  runWithClient<T>(callback: (client: WasmMssClientInstance) => Promise<T>): Promise<T>;
@@ -38,6 +38,10 @@ export class WasmCryptoEngine {
38
38
  this.accessToken = accessToken;
39
39
  this.wasmClient?.setAccessToken(accessToken);
40
40
  }
41
+ async getLocalCryptoHealth() {
42
+ const { checkLocalCryptoHealth } = await import('./local-crypto-health');
43
+ return checkLocalCryptoHealth(() => this.ensureReady());
44
+ }
41
45
  async ensureReady() {
42
46
  try {
43
47
  await this.runWithClient(async (client) => {
package/dist/index.d.ts CHANGED
@@ -3,4 +3,18 @@ export * from './client';
3
3
  export * from './contracts/capabilities.contract';
4
4
  export * from './contracts/commands.contract';
5
5
  export * from './contracts/health.contract';
6
+ export * from './contracts/chat.contract';
7
+ export * from './contracts/user-search.contract';
6
8
  export * from './errors/control-errors';
9
+ export * from './modules/media/media-crypto.contracts';
10
+ export * from './modules/media/media-message.contracts';
11
+ export * from './modules/messages/message.contracts';
12
+ export * from './modules/messages/message-decryption.contracts';
13
+ export * from './modules/messages/message-decryption-state';
14
+ export * from './modules/storage/drive-file-runtime.contracts';
15
+ export * from './modules/storage/drive-file-runtime';
16
+ export * from './modules/storage/drive-key-wrapping.contracts';
17
+ export * from './modules/storage/drive-sharing.contracts';
18
+ export * from './modules/storage/storage-metadata-crypto.contracts';
19
+ export * from './core/local-crypto-health.contracts';
20
+ export * from './core/local-crypto-health';
package/dist/index.js CHANGED
@@ -3,4 +3,18 @@ export * from './client';
3
3
  export * from './contracts/capabilities.contract';
4
4
  export * from './contracts/commands.contract';
5
5
  export * from './contracts/health.contract';
6
+ export * from './contracts/chat.contract';
7
+ export * from './contracts/user-search.contract';
6
8
  export * from './errors/control-errors';
9
+ export * from './modules/media/media-crypto.contracts';
10
+ export * from './modules/media/media-message.contracts';
11
+ export * from './modules/messages/message.contracts';
12
+ export * from './modules/messages/message-decryption.contracts';
13
+ export * from './modules/messages/message-decryption-state';
14
+ export * from './modules/storage/drive-file-runtime.contracts';
15
+ export * from './modules/storage/drive-file-runtime';
16
+ export * from './modules/storage/drive-key-wrapping.contracts';
17
+ export * from './modules/storage/drive-sharing.contracts';
18
+ export * from './modules/storage/storage-metadata-crypto.contracts';
19
+ export * from './core/local-crypto-health.contracts';
20
+ export * from './core/local-crypto-health';
@@ -4,8 +4,9 @@ export declare class ChatsClient {
4
4
  constructor(http: HttpClient);
5
5
  list(): Promise<any[]>;
6
6
  getDetails(chatId: string): Promise<any>;
7
- createDirect(targetUserId: string): Promise<any>;
8
- createGroup(name: string, userIds: string[]): Promise<any>;
7
+ createDirect(input: any): Promise<any>;
8
+ createGroup(input: any): Promise<any>;
9
+ searchUsers(query: string): Promise<any>;
9
10
  archive(chatId: string): Promise<any>;
10
11
  hide(chatId: string): Promise<any>;
11
12
  }
@@ -10,11 +10,15 @@ export class ChatsClient {
10
10
  async getDetails(chatId) {
11
11
  return this.http.get(`/link/v1/chats/${chatId}`);
12
12
  }
13
- async createDirect(targetUserId) {
14
- return this.http.post('/link/v1/chats/direct', { targetUserId });
13
+ async createDirect(input) {
14
+ return this.http.post('/link/v1/chats/direct', input);
15
15
  }
16
- async createGroup(name, userIds) {
17
- return this.http.post('/link/v1/chats/group', { name, userIds });
16
+ async createGroup(input) {
17
+ return this.http.post('/link/v1/chats/group', input);
18
+ }
19
+ async searchUsers(query) {
20
+ return this.http.get('/link/v1/users/search', { params: { q: query } })
21
+ .then(response => response.users);
18
22
  }
19
23
  async archive(chatId) {
20
24
  return this.http.post(`/link/v1/chats/${chatId}/archive`);
@@ -2,7 +2,16 @@ import { HttpClient } from '../../core/http-client';
2
2
  export declare class MessagesClient {
3
3
  private readonly http;
4
4
  constructor(http: HttpClient);
5
- list(chatId: string, limit?: number, before?: string, after?: string): Promise<any>;
6
- markDelivered(chatId: string, throughMessageId: string, limit?: number): Promise<any>;
7
- markRead(chatId: string, throughMessageId: string, limit?: number): Promise<any>;
5
+ list(input: any): Promise<any>;
6
+ markDelivered(input: any): Promise<any>;
7
+ markRead(input: any): Promise<any>;
8
+ createMediaUpload(input: any): Promise<any>;
9
+ getMediaAssetUrl(assetId: string): Promise<any>;
10
+ downloadMediaAsset(assetId: string): Promise<{
11
+ blob: Blob;
12
+ fileName: string | undefined;
13
+ }>;
14
+ getSyncCheckpoint(): Promise<any>;
15
+ getSyncEvents(input?: any): Promise<any>;
16
+ acknowledgeSyncCheckpoint(input: any): Promise<any>;
8
17
  }
@@ -4,21 +4,60 @@ export class MessagesClient {
4
4
  constructor(http) {
5
5
  this.http = http;
6
6
  }
7
- async list(chatId, limit = 30, before, after) {
7
+ async list(input) {
8
+ const { chatId, before, after, limit = 30 } = input;
8
9
  return this.http.get(`/link/v1/chats/${chatId}/messages`, {
9
10
  params: { limit, before, after }
10
11
  });
11
12
  }
12
- async markDelivered(chatId, throughMessageId, limit) {
13
+ async markDelivered(input) {
14
+ const { chatId, throughMessageId, limit } = input;
13
15
  return this.http.post(`/link/v1/chats/${chatId}/messages/delivered`, {
14
16
  throughMessageId,
15
17
  limit
16
18
  });
17
19
  }
18
- async markRead(chatId, throughMessageId, limit) {
20
+ async markRead(input) {
21
+ const { chatId, throughMessageId, limit } = input;
19
22
  return this.http.post(`/link/v1/chats/${chatId}/messages/read`, {
20
23
  throughMessageId,
21
24
  limit
22
25
  });
23
26
  }
27
+ async createMediaUpload(input) {
28
+ return this.http.post('/link/v1/media/uploads', input);
29
+ }
30
+ async getMediaAssetUrl(assetId) {
31
+ return this.http.get(`/link/v1/media/assets/${assetId}/url`);
32
+ }
33
+ async downloadMediaAsset(assetId) {
34
+ const res = await fetch(`${this.http['baseUrl']}/link/v1/media/assets/${assetId}/download`, {
35
+ headers: await this.http['getHeaders']()
36
+ });
37
+ if (!res.ok)
38
+ throw new Error('Download failed');
39
+ const blob = await res.blob();
40
+ const disposition = res.headers.get('content-disposition');
41
+ let fileName;
42
+ if (disposition && disposition.indexOf('filename=') !== -1) {
43
+ const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
44
+ const matches = filenameRegex.exec(disposition);
45
+ if (matches != null && matches[1]) {
46
+ fileName = matches[1].replace(/['"]/g, '');
47
+ }
48
+ }
49
+ return { blob, fileName };
50
+ }
51
+ async getSyncCheckpoint() {
52
+ return this.http.get('/link/v1/sync/checkpoint');
53
+ }
54
+ async getSyncEvents(input = {}) {
55
+ const { cursor, limit = 100 } = input;
56
+ return this.http.get('/link/v1/sync/events', {
57
+ params: { cursor, limit }
58
+ });
59
+ }
60
+ async acknowledgeSyncCheckpoint(input) {
61
+ return this.http.post('/link/v1/sync/ack', input);
62
+ }
24
63
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@msssystems/mss-link-sdk",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Official managed application SDK for MSS ecosystem",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",